From 1c55b335b196a30e1b2e7102abdb7ca6fb17bc0a Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 20 Sep 2022 10:38:22 +0300 Subject: [PATCH 001/229] add gov integration tests --- novawallet.xcodeproj/project.pbxproj | 40 +++++++++++++ .../Model/ChainRegistry/ChainModel.swift | 1 + .../Governance+StorageCodingPath.swift | 7 +++ .../Types/Governance/Governance.swift | 6 ++ .../Types/Governance/ReferendumInfo.swift | 59 ++++++++++++++++++ .../ReferendumFetchTests.swift | 60 +++++++++++++++++++ 6 files changed, 173 insertions(+) create mode 100644 novawallet/Common/Substrate/Types/Governance/Governance+StorageCodingPath.swift create mode 100644 novawallet/Common/Substrate/Types/Governance/Governance.swift create mode 100644 novawallet/Common/Substrate/Types/Governance/ReferendumInfo.swift create mode 100644 novawalletIntegrationTests/ReferendumFetchTests.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 4a61a7729c..dbe57e79c9 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1123,6 +1123,10 @@ 847999B628894FE200D1BAD2 /* AccountInputViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847999B528894FE200D1BAD2 /* AccountInputViewDelegate.swift */; }; 847999B82889510C00D1BAD2 /* TextInputViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847999B72889510C00D1BAD2 /* TextInputViewDelegate.swift */; }; 8479F31426CD9A0E005D8D24 /* ChainRegistryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8479F31326CD9A0E005D8D24 /* ChainRegistryIntegrationTests.swift */; }; + 847A25C328D84A9C006AC9F5 /* ReferendumFetchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */; }; + 847A25C628D84BE2006AC9F5 /* Governance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C528D84BE2006AC9F5 /* Governance.swift */; }; + 847A25C828D84C0A006AC9F5 /* Governance+StorageCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C728D84C0A006AC9F5 /* Governance+StorageCodingPath.swift */; }; + 847A25CA28D85204006AC9F5 /* ReferendumInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */; }; 847A6C0928817DC700477F77 /* AssetListBaseInteractorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A6C0828817DC700477F77 /* AssetListBaseInteractorProtocol.swift */; }; 847A6C0B28817E4000477F77 /* AssetListBaseInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A6C0A28817E4000477F77 /* AssetListBaseInteractor.swift */; }; 847ABE3128532E1B00851218 /* ConsesusType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847ABE3028532E1B00851218 /* ConsesusType.swift */; }; @@ -3835,6 +3839,10 @@ 847999B528894FE200D1BAD2 /* AccountInputViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountInputViewDelegate.swift; sourceTree = ""; }; 847999B72889510C00D1BAD2 /* TextInputViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextInputViewDelegate.swift; sourceTree = ""; }; 8479F31326CD9A0E005D8D24 /* ChainRegistryIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainRegistryIntegrationTests.swift; sourceTree = ""; }; + 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFetchTests.swift; sourceTree = ""; }; + 847A25C528D84BE2006AC9F5 /* Governance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Governance.swift; sourceTree = ""; }; + 847A25C728D84C0A006AC9F5 /* Governance+StorageCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Governance+StorageCodingPath.swift"; sourceTree = ""; }; + 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumInfo.swift; sourceTree = ""; }; 847A6C0828817DC700477F77 /* AssetListBaseInteractorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListBaseInteractorProtocol.swift; sourceTree = ""; }; 847A6C0A28817E4000477F77 /* AssetListBaseInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListBaseInteractor.swift; sourceTree = ""; }; 847ABE3028532E1B00851218 /* ConsesusType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsesusType.swift; sourceTree = ""; }; @@ -6969,6 +6977,7 @@ 84264EE0285B6C6700BF6D4A /* XcmTransfersSyncTests.swift */, 844133BA2860528500845987 /* XcmTransfersFeeTests.swift */, 84BFE8A128C2420A00140F1F /* AutocompounDelegateStakeTests.swift */, + 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */, ); path = novawalletIntegrationTests; sourceTree = ""; @@ -6976,6 +6985,7 @@ 8438E1DC24C18F11001BDB13 /* Types */ = { isa = PBXGroup; children = ( + 847A25C428D84BC9006AC9F5 /* Governance */, 84BFE89A28C23A0900140F1F /* AutomationTime */, 84FB9E18285C57C000B42FC0 /* Xcm */, 848DAEFC282293BD00D56F55 /* ParachainStaking */, @@ -8024,6 +8034,31 @@ path = Address; sourceTree = ""; }; + 847A25C028D84A3D006AC9F5 /* Governance */ = { + isa = PBXGroup; + children = ( + 847A25C128D84A48006AC9F5 /* Operation */, + ); + path = Governance; + sourceTree = ""; + }; + 847A25C128D84A48006AC9F5 /* Operation */ = { + isa = PBXGroup; + children = ( + ); + path = Operation; + sourceTree = ""; + }; + 847A25C428D84BC9006AC9F5 /* Governance */ = { + isa = PBXGroup; + children = ( + 847A25C528D84BE2006AC9F5 /* Governance.swift */, + 847A25C728D84C0A006AC9F5 /* Governance+StorageCodingPath.swift */, + 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */, + ); + path = Governance; + sourceTree = ""; + }; 847A6C0728817DAD00477F77 /* Base */ = { isa = PBXGroup; children = ( @@ -8333,6 +8368,7 @@ 849013D124A92686008F705E /* Common */ = { isa = PBXGroup; children = ( + 847A25C028D84A3D006AC9F5 /* Governance */, 8444406D28AA57D600446D22 /* Ledger */, 88A0E0FB28A284C700A9C940 /* Currency */, 849014C924AA8B75008F705E /* Animation */, @@ -13379,6 +13415,7 @@ 844133BD2860532C00845987 /* XcmTransfersSync+Setup.swift in Sources */, 8499FE7D27BE61E000712589 /* UniquesIntegrationTests.swift in Sources */, 84216FD82827A35F00479375 /* ParaStakingRewardCalculatorTests.swift in Sources */, + 847A25C328D84A9C006AC9F5 /* ReferendumFetchTests.swift in Sources */, 84161DB627C39013005DF668 /* NftSyncIntegrationTests.swift in Sources */, 84FACB6625F56D5000F32ED4 /* CalculatorServiceTests.swift in Sources */, ); @@ -14022,6 +14059,7 @@ 8463A72D25E3A8E1003B8160 /* ChainStorageDecodedItem.swift in Sources */, 84DD5F30263D84F300425ACF /* RuntimeConstantFetching.swift in Sources */, 84B64E412704569D00914E88 /* StakingLocalSubscriptionHandler.swift in Sources */, + 847A25C828D84C0A006AC9F5 /* Governance+StorageCodingPath.swift in Sources */, 848FFE9525E6DF2200652AA5 /* PagedKeysRequest.swift in Sources */, 8428766B24ADF51D00D91AD8 /* UIViewController+Modal.swift in Sources */, 84468A09286662E000BCBE00 /* CrossChainTransferSetupInteractor.swift in Sources */, @@ -14555,6 +14593,7 @@ 8473F4B6282BE488007CC55A /* StakingRelaychainProtocols.swift in Sources */, 844D2A40281B0ED70049CF5E /* StackTableHeaderCell.swift in Sources */, 84A2A60A26B82B35000C6C6C /* ValidatorOperationFactory+Protocol.swift in Sources */, + 847A25C628D84BE2006AC9F5 /* Governance.swift in Sources */, 88421055289BBA8D00306F2C /* CurrencyViewLayout.swift in Sources */, 845C407D2702812E00BFA50B /* StakingAccountUpdatingService.swift in Sources */, 8430D6C92801A2B500FFB6AE /* WebSocketProtocols.swift in Sources */, @@ -15194,6 +15233,7 @@ 841E5536282CDB9E00C8438F /* StakingMainPresenterFactory+Relaychain.swift in Sources */, F409673326B29C9B008CD244 /* RewardAnalyticsWidgetViewModel.swift in Sources */, 8499FEC827BF73F400712589 /* StorageKeyFactory+Size.swift in Sources */, + 847A25CA28D85204006AC9F5 /* ReferendumInfo.swift in Sources */, 5869563D0EA593FBD02C169C /* StakingPayoutConfirmationProtocols.swift in Sources */, 846B749828B4BA0500C39B93 /* LedgerAccountsStore.swift in Sources */, 844ADE7728CA7F7100EE29F7 /* ParaStkYieldBoostSetupPresenter+ViewUpdate.swift in Sources */, diff --git a/novawallet/Common/Model/ChainRegistry/ChainModel.swift b/novawallet/Common/Model/ChainRegistry/ChainModel.swift index 79d3c80d18..70c726d637 100644 --- a/novawallet/Common/Model/ChainRegistry/ChainModel.swift +++ b/novawallet/Common/Model/ChainRegistry/ChainModel.swift @@ -154,4 +154,5 @@ enum ChainOptions: String, Codable { case ethereumBased case testnet case crowdloans + case governance } diff --git a/novawallet/Common/Substrate/Types/Governance/Governance+StorageCodingPath.swift b/novawallet/Common/Substrate/Types/Governance/Governance+StorageCodingPath.swift new file mode 100644 index 0000000000..80015c0d32 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Governance/Governance+StorageCodingPath.swift @@ -0,0 +1,7 @@ +import Foundation + +extension Governance { + static var referendumInfo: StorageCodingPath { + StorageCodingPath(moduleName: "Referenda", itemName: "ReferendumInfoFor") + } +} diff --git a/novawallet/Common/Substrate/Types/Governance/Governance.swift b/novawallet/Common/Substrate/Types/Governance/Governance.swift new file mode 100644 index 0000000000..ab7aa045db --- /dev/null +++ b/novawallet/Common/Substrate/Types/Governance/Governance.swift @@ -0,0 +1,6 @@ +import Foundation + +enum Governance { + typealias TrackId = UInt16 + typealias ReferendumIndex = UInt64 +} diff --git a/novawallet/Common/Substrate/Types/Governance/ReferendumInfo.swift b/novawallet/Common/Substrate/Types/Governance/ReferendumInfo.swift new file mode 100644 index 0000000000..abbfc3a1b5 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Governance/ReferendumInfo.swift @@ -0,0 +1,59 @@ +import Foundation +import SubstrateSdk + +enum ReferendumInfo: Decodable { + struct OngoingStatus: Decodable { + @StringCodable var track: Governance.TrackId + } + + case ongoing(_ status: OngoingStatus) + case approved + case rejected + case cancelled + case timedOut + case killed + case unknown + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "Ongoing": + let status = try container.decode(OngoingStatus.self) + self = .ongoing(status) + case "Approved": + self = .approved + case "Rejected": + self = .rejected + case "Cancelled": + self = .cancelled + case "TimedOut": + self = .timedOut + case "Killed": + self = .killed + default: + self = .unknown + } + } +} + +struct ReferendumIndexKey: JSONListConvertible, Hashable { + let referendumIndex: Governance.ReferendumIndex + + init(jsonList: [JSON], context: [CodingUserInfoKey: Any]?) throws { + let expectedFieldsCount = 1 + let actualFieldsCount = jsonList.count + guard expectedFieldsCount == actualFieldsCount else { + throw JSONListConvertibleError.unexpectedNumberOfItems( + expected: expectedFieldsCount, + actual: actualFieldsCount + ) + } + + referendumIndex = try jsonList[0].map( + to: StringScaleMapper.self, + with: context + ).value + } +} diff --git a/novawalletIntegrationTests/ReferendumFetchTests.swift b/novawalletIntegrationTests/ReferendumFetchTests.swift new file mode 100644 index 0000000000..f2d05a5a94 --- /dev/null +++ b/novawalletIntegrationTests/ReferendumFetchTests.swift @@ -0,0 +1,60 @@ +import XCTest +@testable import novawallet +import SubstrateSdk +import RobinHood + +class ReferendumFetchTests: XCTestCase { + func testFetchAllOnchainReferendums() { + // given + + let storageFacade = SubstrateStorageTestFacade() + let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) + let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" + let operationQueue = OperationQueue() + + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + guard let connection = chainRegistry.getConnection(for: chainId) else { + XCTFail("Can't get connection for chain id \(chainId)") + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + XCTFail("Can't get runtime provider for chain id \(chainId)") + return + } + + // when + + let request = UnkeyedRemoteStorageRequest(storagePath: Governance.referendumInfo) + + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let wrapper: CompoundOperationWrapper<[ReferendumIndexKey: ReferendumInfo]> = requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: request.storagePath, + factory: { + try codingFactoryOperation.extractNoCancellableResultData() + }, + at: nil + ) + + wrapper.addDependency(operations: [codingFactoryOperation]) + + let operations = [codingFactoryOperation] + wrapper.allOperations + operationQueue.addOperations(operations, waitUntilFinished: true) + + // then + + do { + let referendums = try wrapper.targetOperation.extractNoCancellableResultData() + Logger.shared.info("Referendums: \(referendums)") + } catch { + XCTFail("Unexpected error \(error)") + } + } +} From adc4efaf42e265bdae4dbb268af107497d7c16d5 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 21 Sep 2022 00:13:55 +0300 Subject: [PATCH 002/229] add ongoing status handling --- novawallet.xcodeproj/project.pbxproj | 60 +++++++++++++++---- .../ConvictionVoting/ConvictionVoting.swift | 3 + .../ConvictionVotingTally.swift | 11 ++++ .../Referenda+StorageCodingPath.swift} | 2 +- .../Referenda.swift} | 2 +- .../Types/Referenda/ReferendaDeposit.swift | 10 ++++ .../ReferendumInfo.swift | 18 +++++- .../Types/Scheduler/OnChainDispatchTime.swift | 27 +++++++++ .../Types/Scheduler/OnChainScheduler.swift | 3 + .../ReferendumFetchTests.swift | 2 +- 10 files changed, 120 insertions(+), 18 deletions(-) create mode 100644 novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift create mode 100644 novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingTally.swift rename novawallet/Common/Substrate/Types/{Governance/Governance+StorageCodingPath.swift => Referenda/Referenda+StorageCodingPath.swift} (87%) rename novawallet/Common/Substrate/Types/{Governance/Governance.swift => Referenda/Referenda.swift} (83%) create mode 100644 novawallet/Common/Substrate/Types/Referenda/ReferendaDeposit.swift rename novawallet/Common/Substrate/Types/{Governance => Referenda}/ReferendumInfo.swift (70%) create mode 100644 novawallet/Common/Substrate/Types/Scheduler/OnChainDispatchTime.swift create mode 100644 novawallet/Common/Substrate/Types/Scheduler/OnChainScheduler.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index dbe57e79c9..1df8cccc00 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1124,8 +1124,8 @@ 847999B82889510C00D1BAD2 /* TextInputViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847999B72889510C00D1BAD2 /* TextInputViewDelegate.swift */; }; 8479F31426CD9A0E005D8D24 /* ChainRegistryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8479F31326CD9A0E005D8D24 /* ChainRegistryIntegrationTests.swift */; }; 847A25C328D84A9C006AC9F5 /* ReferendumFetchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */; }; - 847A25C628D84BE2006AC9F5 /* Governance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C528D84BE2006AC9F5 /* Governance.swift */; }; - 847A25C828D84C0A006AC9F5 /* Governance+StorageCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C728D84C0A006AC9F5 /* Governance+StorageCodingPath.swift */; }; + 847A25C628D84BE2006AC9F5 /* Referenda.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C528D84BE2006AC9F5 /* Referenda.swift */; }; + 847A25C828D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */; }; 847A25CA28D85204006AC9F5 /* ReferendumInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */; }; 847A6C0928817DC700477F77 /* AssetListBaseInteractorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A6C0828817DC700477F77 /* AssetListBaseInteractorProtocol.swift */; }; 847A6C0B28817E4000477F77 /* AssetListBaseInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A6C0A28817E4000477F77 /* AssetListBaseInteractor.swift */; }; @@ -1225,6 +1225,11 @@ 848B59C228BCC1E60009543C /* LedgerAddAccountConfirmationInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848B59C128BCC1E60009543C /* LedgerAddAccountConfirmationInteractor.swift */; }; 848B59C428BCD1BD0009543C /* MessageSheetContentLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848B59C328BCD1BD0009543C /* MessageSheetContentLabel.swift */; }; 848C3D0926248A3B005481C3 /* TransferCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848C3D0826248A3B005481C3 /* TransferCall.swift */; }; + 848CC93B28D9F6A5009EB4B0 /* OnChainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848CC93A28D9F6A5009EB4B0 /* OnChainScheduler.swift */; }; + 848CC93D28D9F6D8009EB4B0 /* OnChainDispatchTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848CC93C28D9F6D8009EB4B0 /* OnChainDispatchTime.swift */; }; + 848CC93F28D9F90D009EB4B0 /* ReferendaDeposit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848CC93E28D9F90D009EB4B0 /* ReferendaDeposit.swift */; }; + 848CC94428D9FBDA009EB4B0 /* ConvictionVoting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848CC94328D9FBDA009EB4B0 /* ConvictionVoting.swift */; }; + 848CC94628D9FC46009EB4B0 /* ConvictionVotingTally.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848CC94528D9FC46009EB4B0 /* ConvictionVotingTally.swift */; }; 848CCB442832EE9B00A1FD00 /* GeneralStorageSubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848CCB432832EE9B00A1FD00 /* GeneralStorageSubscriptionFactory.swift */; }; 848CCB462832EF3400A1FD00 /* GeneralLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848CCB452832EF3400A1FD00 /* GeneralLocalStorageSubscriber.swift */; }; 848CCB482832EF4400A1FD00 /* GeneralLocalStorageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848CCB472832EF4400A1FD00 /* GeneralLocalStorageHandler.swift */; }; @@ -3840,8 +3845,8 @@ 847999B72889510C00D1BAD2 /* TextInputViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextInputViewDelegate.swift; sourceTree = ""; }; 8479F31326CD9A0E005D8D24 /* ChainRegistryIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainRegistryIntegrationTests.swift; sourceTree = ""; }; 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFetchTests.swift; sourceTree = ""; }; - 847A25C528D84BE2006AC9F5 /* Governance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Governance.swift; sourceTree = ""; }; - 847A25C728D84C0A006AC9F5 /* Governance+StorageCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Governance+StorageCodingPath.swift"; sourceTree = ""; }; + 847A25C528D84BE2006AC9F5 /* Referenda.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Referenda.swift; sourceTree = ""; }; + 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Referenda+StorageCodingPath.swift"; sourceTree = ""; }; 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumInfo.swift; sourceTree = ""; }; 847A6C0828817DC700477F77 /* AssetListBaseInteractorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListBaseInteractorProtocol.swift; sourceTree = ""; }; 847A6C0A28817E4000477F77 /* AssetListBaseInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListBaseInteractor.swift; sourceTree = ""; }; @@ -3942,6 +3947,11 @@ 848B59C128BCC1E60009543C /* LedgerAddAccountConfirmationInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LedgerAddAccountConfirmationInteractor.swift; sourceTree = ""; }; 848B59C328BCD1BD0009543C /* MessageSheetContentLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSheetContentLabel.swift; sourceTree = ""; }; 848C3D0826248A3B005481C3 /* TransferCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferCall.swift; sourceTree = ""; }; + 848CC93A28D9F6A5009EB4B0 /* OnChainScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnChainScheduler.swift; sourceTree = ""; }; + 848CC93C28D9F6D8009EB4B0 /* OnChainDispatchTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnChainDispatchTime.swift; sourceTree = ""; }; + 848CC93E28D9F90D009EB4B0 /* ReferendaDeposit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendaDeposit.swift; sourceTree = ""; }; + 848CC94328D9FBDA009EB4B0 /* ConvictionVoting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvictionVoting.swift; sourceTree = ""; }; + 848CC94528D9FC46009EB4B0 /* ConvictionVotingTally.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvictionVotingTally.swift; sourceTree = ""; }; 848CCB432832EE9B00A1FD00 /* GeneralStorageSubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralStorageSubscriptionFactory.swift; sourceTree = ""; }; 848CCB452832EF3400A1FD00 /* GeneralLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralLocalStorageSubscriber.swift; sourceTree = ""; }; 848CCB472832EF4400A1FD00 /* GeneralLocalStorageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralLocalStorageHandler.swift; sourceTree = ""; }; @@ -6985,7 +6995,9 @@ 8438E1DC24C18F11001BDB13 /* Types */ = { isa = PBXGroup; children = ( - 847A25C428D84BC9006AC9F5 /* Governance */, + 848CC94228D9FBBE009EB4B0 /* ConvictionVoting */, + 848CC93928D9F68C009EB4B0 /* Scheduler */, + 847A25C428D84BC9006AC9F5 /* Referenda */, 84BFE89A28C23A0900140F1F /* AutomationTime */, 84FB9E18285C57C000B42FC0 /* Xcm */, 848DAEFC282293BD00D56F55 /* ParachainStaking */, @@ -8049,14 +8061,15 @@ path = Operation; sourceTree = ""; }; - 847A25C428D84BC9006AC9F5 /* Governance */ = { + 847A25C428D84BC9006AC9F5 /* Referenda */ = { isa = PBXGroup; children = ( - 847A25C528D84BE2006AC9F5 /* Governance.swift */, - 847A25C728D84C0A006AC9F5 /* Governance+StorageCodingPath.swift */, + 847A25C528D84BE2006AC9F5 /* Referenda.swift */, + 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */, 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */, + 848CC93E28D9F90D009EB4B0 /* ReferendaDeposit.swift */, ); - path = Governance; + path = Referenda; sourceTree = ""; }; 847A6C0728817DAD00477F77 /* Base */ = { @@ -8200,6 +8213,24 @@ path = AccountAddFlow; sourceTree = ""; }; + 848CC93928D9F68C009EB4B0 /* Scheduler */ = { + isa = PBXGroup; + children = ( + 848CC93A28D9F6A5009EB4B0 /* OnChainScheduler.swift */, + 848CC93C28D9F6D8009EB4B0 /* OnChainDispatchTime.swift */, + ); + path = Scheduler; + sourceTree = ""; + }; + 848CC94228D9FBBE009EB4B0 /* ConvictionVoting */ = { + isa = PBXGroup; + children = ( + 848CC94328D9FBDA009EB4B0 /* ConvictionVoting.swift */, + 848CC94528D9FC46009EB4B0 /* ConvictionVotingTally.swift */, + ); + path = ConvictionVoting; + sourceTree = ""; + }; 848DAEFC282293BD00D56F55 /* ParachainStaking */ = { isa = PBXGroup; children = ( @@ -8368,7 +8399,6 @@ 849013D124A92686008F705E /* Common */ = { isa = PBXGroup; children = ( - 847A25C028D84A3D006AC9F5 /* Governance */, 8444406D28AA57D600446D22 /* Ledger */, 88A0E0FB28A284C700A9C940 /* Currency */, 849014C924AA8B75008F705E /* Animation */, @@ -8403,6 +8433,7 @@ 849013D224A9268D008F705E /* Modules */ = { isa = PBXGroup; children = ( + 847A25C028D84A3D006AC9F5 /* Governance */, 848FD1A628AE314F00CCD9E2 /* Ledger */, 8842104D289BBA8D00306F2C /* Currency */, 95ED25232B568F2C7DA953CC /* MessageSheet */, @@ -13866,6 +13897,7 @@ 849A4EFA279ABC8800AB6709 /* AssetBalanceMapper.swift in Sources */, 8490147724A94A37008F705E /* RootPresenter.swift in Sources */, 8428765724ADDE0200D91AD8 /* SettingsTableViewCell.swift in Sources */, + 848CC93F28D9F90D009EB4B0 /* ReferendaDeposit.swift in Sources */, 8401AE8D2641EF7B000B03E3 /* NetworkFeeConfirmView.swift in Sources */, 841AAC2F26F73E0C00F0A25E /* LocalStorageKeyFactory.swift in Sources */, 843C49DF24DF3CB300B71DDA /* AccountImportMetadata.swift in Sources */, @@ -14059,7 +14091,7 @@ 8463A72D25E3A8E1003B8160 /* ChainStorageDecodedItem.swift in Sources */, 84DD5F30263D84F300425ACF /* RuntimeConstantFetching.swift in Sources */, 84B64E412704569D00914E88 /* StakingLocalSubscriptionHandler.swift in Sources */, - 847A25C828D84C0A006AC9F5 /* Governance+StorageCodingPath.swift in Sources */, + 847A25C828D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift in Sources */, 848FFE9525E6DF2200652AA5 /* PagedKeysRequest.swift in Sources */, 8428766B24ADF51D00D91AD8 /* UIViewController+Modal.swift in Sources */, 84468A09286662E000BCBE00 /* CrossChainTransferSetupInteractor.swift in Sources */, @@ -14166,6 +14198,7 @@ AE2C32DC271D90DD00D57C91 /* MetaAccountOperationFactory.swift in Sources */, 84D8F16F24D8451F00AF43E9 /* CryptoType+ViewModel.swift in Sources */, AEBE16E6262EA7C100DF257C /* StakingErrors.swift in Sources */, + 848CC93B28D9F6A5009EB4B0 /* OnChainScheduler.swift in Sources */, AEAC68F526E9F93B00346599 /* CoingeckoDefinitions.swift in Sources */, 8410DBCB26EA31DE00FE1738 /* AccountProviderFactory.swift in Sources */, 841E554F282E2C0300C8438F /* StakingParachainInteractor+InputProtocol.swift in Sources */, @@ -14567,6 +14600,7 @@ 84FF267C28494B13003EC78D /* ParaStkStakeSetupPresenter+StartStaking.swift in Sources */, 842BDB2A278C4F3C00AB4B5A /* DAppBrowserAuthorizingState.swift in Sources */, 84FEADF228783F55001DFC26 /* BaseParaStakingRewardCalculatoService.swift in Sources */, + 848CC93D28D9F6D8009EB4B0 /* OnChainDispatchTime.swift in Sources */, 841E5534282CD9A900C8438F /* StakingType.swift in Sources */, 84CFBC6528756CCB00E93EDA /* EthereumError+Presentable.swift in Sources */, 847C966325536455002D288F /* ExportRestoreJsonViewFactory.swift in Sources */, @@ -14593,7 +14627,7 @@ 8473F4B6282BE488007CC55A /* StakingRelaychainProtocols.swift in Sources */, 844D2A40281B0ED70049CF5E /* StackTableHeaderCell.swift in Sources */, 84A2A60A26B82B35000C6C6C /* ValidatorOperationFactory+Protocol.swift in Sources */, - 847A25C628D84BE2006AC9F5 /* Governance.swift in Sources */, + 847A25C628D84BE2006AC9F5 /* Referenda.swift in Sources */, 88421055289BBA8D00306F2C /* CurrencyViewLayout.swift in Sources */, 845C407D2702812E00BFA50B /* StakingAccountUpdatingService.swift in Sources */, 8430D6C92801A2B500FFB6AE /* WebSocketProtocols.swift in Sources */, @@ -14765,6 +14799,7 @@ 4A520B7081BE2D7604B69354 /* AccountImportWireframe.swift in Sources */, 840B3D6C2899CD5A00DA1DA9 /* ParitySignerScanMatcher.swift in Sources */, F4433D5F26C166470002A91E /* AnalyticsValidatorsView.swift in Sources */, + 848CC94428D9FBDA009EB4B0 /* ConvictionVoting.swift in Sources */, 846AF8422525BDBF00868F37 /* WalletNetworkFacade+Price.swift in Sources */, 7D281FEA78E2E5F44990C184 /* AccountImportPresenter.swift in Sources */, 6C56AB4AE63AB2DC73DE98E0 /* AccountImportInteractor.swift in Sources */, @@ -15557,6 +15592,7 @@ 847999B12888A4FF00D1BAD2 /* SwitchAccount+CreateWatchOnlyWireframe.swift in Sources */, 8487580727EDEB9600495306 /* BorderedIconLabelView.swift in Sources */, 84AE7AAD27D3839D00495267 /* StackCellViewModel.swift in Sources */, + 848CC94628D9FC46009EB4B0 /* ConvictionVotingTally.swift in Sources */, CD9359A2720F2EE1D4E09DF6 /* DAppTxDetailsWireframe.swift in Sources */, 0E364B6F05D390069D049CC2 /* DAppTxDetailsPresenter.swift in Sources */, 9BADFCBF3AF5186094DB8D67 /* DAppTxDetailsInteractor.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift new file mode 100644 index 0000000000..0e1154deec --- /dev/null +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -0,0 +1,3 @@ +import Foundation + +enum ConvictionVoting {} diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingTally.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingTally.swift new file mode 100644 index 0000000000..7215a7354f --- /dev/null +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingTally.swift @@ -0,0 +1,11 @@ +import Foundation +import SubstrateSdk +import BigInt + +extension ConvictionVoting { + struct Tally: Decodable { + @StringCodable var ayes: BigUInt + @StringCodable var nays: BigUInt + @StringCodable var support: BigUInt + } +} diff --git a/novawallet/Common/Substrate/Types/Governance/Governance+StorageCodingPath.swift b/novawallet/Common/Substrate/Types/Referenda/Referenda+StorageCodingPath.swift similarity index 87% rename from novawallet/Common/Substrate/Types/Governance/Governance+StorageCodingPath.swift rename to novawallet/Common/Substrate/Types/Referenda/Referenda+StorageCodingPath.swift index 80015c0d32..adf78477c0 100644 --- a/novawallet/Common/Substrate/Types/Governance/Governance+StorageCodingPath.swift +++ b/novawallet/Common/Substrate/Types/Referenda/Referenda+StorageCodingPath.swift @@ -1,6 +1,6 @@ import Foundation -extension Governance { +extension Referenda { static var referendumInfo: StorageCodingPath { StorageCodingPath(moduleName: "Referenda", itemName: "ReferendumInfoFor") } diff --git a/novawallet/Common/Substrate/Types/Governance/Governance.swift b/novawallet/Common/Substrate/Types/Referenda/Referenda.swift similarity index 83% rename from novawallet/Common/Substrate/Types/Governance/Governance.swift rename to novawallet/Common/Substrate/Types/Referenda/Referenda.swift index ab7aa045db..c049673666 100644 --- a/novawallet/Common/Substrate/Types/Governance/Governance.swift +++ b/novawallet/Common/Substrate/Types/Referenda/Referenda.swift @@ -1,6 +1,6 @@ import Foundation -enum Governance { +enum Referenda { typealias TrackId = UInt16 typealias ReferendumIndex = UInt64 } diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendaDeposit.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendaDeposit.swift new file mode 100644 index 0000000000..4bc80c7536 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendaDeposit.swift @@ -0,0 +1,10 @@ +import Foundation +import SubstrateSdk +import BigInt + +extension Referenda { + struct Deposit: Decodable { + let who: AccountId + @StringCodable var amount: BigUInt + } +} diff --git a/novawallet/Common/Substrate/Types/Governance/ReferendumInfo.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift similarity index 70% rename from novawallet/Common/Substrate/Types/Governance/ReferendumInfo.swift rename to novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift index abbfc3a1b5..c0ff6f2834 100644 --- a/novawallet/Common/Substrate/Types/Governance/ReferendumInfo.swift +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift @@ -2,8 +2,20 @@ import Foundation import SubstrateSdk enum ReferendumInfo: Decodable { + struct DecidingStatus: Decodable { + @StringCodable var since: BlockNumber + @OptionStringCodable var confirming: BlockNumber? + } + struct OngoingStatus: Decodable { - @StringCodable var track: Governance.TrackId + @StringCodable var track: Referenda.TrackId + @BytesCodable var proposalHash: Data + let enactment: OnChainScheduler.DispatchTime + @StringCodable var submitted: Moment + let decisionDeposit: Referenda.Deposit? + let desiding: DecidingStatus? + let tally: ConvictionVoting.Tally + let inQueue: Bool } case ongoing(_ status: OngoingStatus) @@ -39,7 +51,7 @@ enum ReferendumInfo: Decodable { } struct ReferendumIndexKey: JSONListConvertible, Hashable { - let referendumIndex: Governance.ReferendumIndex + let referendumIndex: Referenda.ReferendumIndex init(jsonList: [JSON], context: [CodingUserInfoKey: Any]?) throws { let expectedFieldsCount = 1 @@ -52,7 +64,7 @@ struct ReferendumIndexKey: JSONListConvertible, Hashable { } referendumIndex = try jsonList[0].map( - to: StringScaleMapper.self, + to: StringScaleMapper.self, with: context ).value } diff --git a/novawallet/Common/Substrate/Types/Scheduler/OnChainDispatchTime.swift b/novawallet/Common/Substrate/Types/Scheduler/OnChainDispatchTime.swift new file mode 100644 index 0000000000..543f46aead --- /dev/null +++ b/novawallet/Common/Substrate/Types/Scheduler/OnChainDispatchTime.swift @@ -0,0 +1,27 @@ +import Foundation +import SubstrateSdk + +extension OnChainScheduler { + enum DispatchTime: Decodable { + case atBlock(_ blockNumber: Moment) + case afterBlock(_ blockNumber: Moment) + case unknown + + init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + + let type = try container.decode(String.self) + + switch type { + case "At": + let blockNumber = try container.decode(StringScaleMapper.self).value + self = .atBlock(blockNumber) + case "After": + let blockNumber = try container.decode(StringScaleMapper.self).value + self = .afterBlock(blockNumber) + default: + self = .unknown + } + } + } +} diff --git a/novawallet/Common/Substrate/Types/Scheduler/OnChainScheduler.swift b/novawallet/Common/Substrate/Types/Scheduler/OnChainScheduler.swift new file mode 100644 index 0000000000..ae238cf604 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Scheduler/OnChainScheduler.swift @@ -0,0 +1,3 @@ +import Foundation + +enum OnChainScheduler {} diff --git a/novawalletIntegrationTests/ReferendumFetchTests.swift b/novawalletIntegrationTests/ReferendumFetchTests.swift index f2d05a5a94..c83d006c27 100644 --- a/novawalletIntegrationTests/ReferendumFetchTests.swift +++ b/novawalletIntegrationTests/ReferendumFetchTests.swift @@ -29,7 +29,7 @@ class ReferendumFetchTests: XCTestCase { // when - let request = UnkeyedRemoteStorageRequest(storagePath: Governance.referendumInfo) + let request = UnkeyedRemoteStorageRequest(storagePath: Referenda.referendumInfo) let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() From 83ff59a9c93aa5e4b828a612d2d3fe8239b11205 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 28 Sep 2022 13:50:31 +0500 Subject: [PATCH 003/229] add conviction votes fetch test --- novawallet.xcodeproj/project.pbxproj | 28 ++- .../ConvictionVoting+StoragePath.swift | 11 ++ .../ConvictionVoting/ConvictionVoting.swift | 165 +++++++++++++++++- .../ConvictionVotingForKey.swift | 23 +++ .../ConvictionVotesFetchTests.swift | 60 +++++++ 5 files changed, 278 insertions(+), 9 deletions(-) create mode 100644 novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+StoragePath.swift create mode 100644 novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingForKey.swift create mode 100644 novawalletIntegrationTests/ConvictionVotesFetchTests.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 89cf72ecbd..04c32b5bb3 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -855,6 +855,9 @@ 8452585127ABC531004F9082 /* AssetsManageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8452585027ABC531004F9082 /* AssetsManageViewModel.swift */; }; 8452585327ABCA07004F9082 /* HideZeroBalancesChanged.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8452585227ABCA07004F9082 /* HideZeroBalancesChanged.swift */; }; 8452585527ABF270004F9082 /* AssetListEmptyCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8452585427ABF270004F9082 /* AssetListEmptyCell.swift */; }; + 84532D5D28E41D8500EF4ADC /* ConvictionVoting+StoragePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84532D5C28E41D8500EF4ADC /* ConvictionVoting+StoragePath.swift */; }; + 84532D5F28E4210E00EF4ADC /* ConvictionVotesFetchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84532D5E28E4210E00EF4ADC /* ConvictionVotesFetchTests.swift */; }; + 84532D6128E4234700EF4ADC /* ConvictionVotingForKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84532D6028E4234700EF4ADC /* ConvictionVotingForKey.swift */; }; 845353BB2886E3B4006C871A /* OnboardingMainViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845353BA2886E3B4006C871A /* OnboardingMainViewLayout.swift */; }; 845353BD2886EB1A006C871A /* ButtonLargeControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845353BC2886EB1A006C871A /* ButtonLargeControl.swift */; }; 8454C21D2632A78900657DAD /* EventRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8454C21C2632A78900657DAD /* EventRecord.swift */; }; @@ -1122,14 +1125,14 @@ 847999B628894FE200D1BAD2 /* AccountInputViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847999B528894FE200D1BAD2 /* AccountInputViewDelegate.swift */; }; 847999B82889510C00D1BAD2 /* TextInputViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847999B72889510C00D1BAD2 /* TextInputViewDelegate.swift */; }; 8479F31426CD9A0E005D8D24 /* ChainRegistryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8479F31326CD9A0E005D8D24 /* ChainRegistryIntegrationTests.swift */; }; - 847A25C328D84A9C006AC9F5 /* ReferendumFetchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */; }; - 847A25C628D84BE2006AC9F5 /* Referenda.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C528D84BE2006AC9F5 /* Referenda.swift */; }; - 847A25C828D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */; }; - 847A25CA28D85204006AC9F5 /* ReferendumInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */; }; 847A25B928D7BB1F006AC9F5 /* BalancesTransferEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25B828D7BB1F006AC9F5 /* BalancesTransferEvent.swift */; }; 847A25BB28D7BB92006AC9F5 /* ExtrinsicProcessor+Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25BA28D7BB92006AC9F5 /* ExtrinsicProcessor+Events.swift */; }; 847A25BD28D7C0E7006AC9F5 /* TokenTransferedEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25BC28D7C0E7006AC9F5 /* TokenTransferedEvent.swift */; }; 847A25BF28D7C2A2006AC9F5 /* AccountIdCodingWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25BE28D7C2A2006AC9F5 /* AccountIdCodingWrapper.swift */; }; + 847A25C328D84A9C006AC9F5 /* ReferendumFetchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */; }; + 847A25C628D84BE2006AC9F5 /* Referenda.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C528D84BE2006AC9F5 /* Referenda.swift */; }; + 847A25C828D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */; }; + 847A25CA28D85204006AC9F5 /* ReferendumInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */; }; 847A6C0928817DC700477F77 /* AssetListBaseInteractorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A6C0828817DC700477F77 /* AssetListBaseInteractorProtocol.swift */; }; 847A6C0B28817E4000477F77 /* AssetListBaseInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A6C0A28817E4000477F77 /* AssetListBaseInteractor.swift */; }; 847ABE3128532E1B00851218 /* ConsesusType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847ABE3028532E1B00851218 /* ConsesusType.swift */; }; @@ -3612,6 +3615,9 @@ 8452585027ABC531004F9082 /* AssetsManageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetsManageViewModel.swift; sourceTree = ""; }; 8452585227ABCA07004F9082 /* HideZeroBalancesChanged.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideZeroBalancesChanged.swift; sourceTree = ""; }; 8452585427ABF270004F9082 /* AssetListEmptyCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListEmptyCell.swift; sourceTree = ""; }; + 84532D5C28E41D8500EF4ADC /* ConvictionVoting+StoragePath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConvictionVoting+StoragePath.swift"; sourceTree = ""; }; + 84532D5E28E4210E00EF4ADC /* ConvictionVotesFetchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvictionVotesFetchTests.swift; sourceTree = ""; }; + 84532D6028E4234700EF4ADC /* ConvictionVotingForKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvictionVotingForKey.swift; sourceTree = ""; }; 845353BA2886E3B4006C871A /* OnboardingMainViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingMainViewLayout.swift; sourceTree = ""; }; 845353BC2886EB1A006C871A /* ButtonLargeControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonLargeControl.swift; sourceTree = ""; }; 8454C21C2632A78900657DAD /* EventRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventRecord.swift; sourceTree = ""; }; @@ -3880,14 +3886,14 @@ 847999B528894FE200D1BAD2 /* AccountInputViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountInputViewDelegate.swift; sourceTree = ""; }; 847999B72889510C00D1BAD2 /* TextInputViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextInputViewDelegate.swift; sourceTree = ""; }; 8479F31326CD9A0E005D8D24 /* ChainRegistryIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainRegistryIntegrationTests.swift; sourceTree = ""; }; - 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFetchTests.swift; sourceTree = ""; }; - 847A25C528D84BE2006AC9F5 /* Referenda.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Referenda.swift; sourceTree = ""; }; - 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Referenda+StorageCodingPath.swift"; sourceTree = ""; }; - 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumInfo.swift; sourceTree = ""; }; 847A25B828D7BB1F006AC9F5 /* BalancesTransferEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalancesTransferEvent.swift; sourceTree = ""; }; 847A25BA28D7BB92006AC9F5 /* ExtrinsicProcessor+Events.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ExtrinsicProcessor+Events.swift"; sourceTree = ""; }; 847A25BC28D7C0E7006AC9F5 /* TokenTransferedEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenTransferedEvent.swift; sourceTree = ""; }; 847A25BE28D7C2A2006AC9F5 /* AccountIdCodingWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountIdCodingWrapper.swift; sourceTree = ""; }; + 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFetchTests.swift; sourceTree = ""; }; + 847A25C528D84BE2006AC9F5 /* Referenda.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Referenda.swift; sourceTree = ""; }; + 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Referenda+StorageCodingPath.swift"; sourceTree = ""; }; + 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumInfo.swift; sourceTree = ""; }; 847A6C0828817DC700477F77 /* AssetListBaseInteractorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListBaseInteractorProtocol.swift; sourceTree = ""; }; 847A6C0A28817E4000477F77 /* AssetListBaseInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListBaseInteractor.swift; sourceTree = ""; }; 847ABE3028532E1B00851218 /* ConsesusType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsesusType.swift; sourceTree = ""; }; @@ -7083,6 +7089,7 @@ 844133BA2860528500845987 /* XcmTransfersFeeTests.swift */, 84BFE8A128C2420A00140F1F /* AutocompounDelegateStakeTests.swift */, 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */, + 84532D5E28E4210E00EF4ADC /* ConvictionVotesFetchTests.swift */, ); path = novawalletIntegrationTests; sourceTree = ""; @@ -8332,6 +8339,8 @@ children = ( 848CC94328D9FBDA009EB4B0 /* ConvictionVoting.swift */, 848CC94528D9FC46009EB4B0 /* ConvictionVotingTally.swift */, + 84532D5C28E41D8500EF4ADC /* ConvictionVoting+StoragePath.swift */, + 84532D6028E4234700EF4ADC /* ConvictionVotingForKey.swift */, ); path = ConvictionVoting; sourceTree = ""; @@ -13565,6 +13574,7 @@ 84264EE1285B6C6700BF6D4A /* XcmTransfersSyncTests.swift in Sources */, 84BFE8A228C2420A00140F1F /* AutocompounDelegateStakeTests.swift in Sources */, F49F49A326A5C45600A25931 /* BabeEraOperationFactoryTests.swift in Sources */, + 84532D5F28E4210E00EF4ADC /* ConvictionVotesFetchTests.swift in Sources */, 84C3420F2831A67200156569 /* BlockTimeEstimationServiceTests.swift in Sources */, 84FACB6A25F5759C00F32ED4 /* AccountCreationHelper.swift in Sources */, 843E9B3827C8CAC1009C143A /* NftDownloadIntegrationTests.swift in Sources */, @@ -13852,6 +13862,7 @@ 841493DC2604C144000D8D1A /* SubscanRewardData.swift in Sources */, 84403D7F25E91BC100494FD4 /* SuperIdentity.swift in Sources */, 8460E71A284D3AF5002896E9 /* ParaStkMinDelegationParams.swift in Sources */, + 84532D5D28E41D8500EF4ADC /* ConvictionVoting+StoragePath.swift in Sources */, 842876A824AE049B00D91AD8 /* SelectionListViewController.swift in Sources */, 84786E1A25FA6A470089DFF7 /* StashItem.swift in Sources */, 848FFE9025E6CF4300652AA5 /* StorageKeyEncodingOperation.swift in Sources */, @@ -14137,6 +14148,7 @@ 8490149924AA7892008F705E /* SharingPresentable.swift in Sources */, 84754C9C2513B26000854599 /* AccountPickerTableViewCell.swift in Sources */, 8472C5B1265CF9C500E2481B /* StakingRewardDestConfirmViewFactory.swift in Sources */, + 84532D6128E4234700EF4ADC /* ConvictionVotingForKey.swift in Sources */, F4488CF226143E0000AEE6DB /* EraRewardPoints.swift in Sources */, 849DF02F26C53DB900B702F4 /* RuntimeSyncEvents.swift in Sources */, 84265E042523D20A005EEE2D /* WalletBaseAmountView.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+StoragePath.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+StoragePath.swift new file mode 100644 index 0000000000..b4e3628df0 --- /dev/null +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+StoragePath.swift @@ -0,0 +1,11 @@ +import Foundation + +extension ConvictionVoting { + static var votingFor: StorageCodingPath { + StorageCodingPath(moduleName: "ConvictionVoting", itemName: "VotingFor") + } + + static var trackLocksFor: StorageCodingPath { + StorageCodingPath(moduleName: "ConvictionVoting", itemName: "ClassLocksFor") + } +} diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index 0e1154deec..e7293a9dfe 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -1,3 +1,166 @@ import Foundation +import SubstrateSdk +import BigInt -enum ConvictionVoting {} +enum ConvictionVoting { + typealias PollIndex = UInt16 + + enum Conviction: UInt8, Decodable { + /// 0.1x votes, unlocked. + case none + /// 1x votes, locked for an enactment period following a successful vote. + case locked1x + /// 2x votes, locked for 2x enactment periods following a successful vote. + case locked2x + /// 3x votes, locked for 4x... + case locked3x + /// 4x votes, locked for 8x... + case locked4x + /// 5x votes, locked for 16x... + case locked5x + /// 6x votes, locked for 32x... + case locked6x + + case unknown + } + + struct Vote: Decodable { + static let ayeMask: UInt8 = 1 << 7 + static var voteMask: UInt8 { ~ayeMask } + + let aye: Bool + let conviction: Conviction + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let compactVote = try container.decode(StringScaleMapper.self).value + + aye = (compactVote & Self.ayeMask) == Self.ayeMask + let rawConviction = compactVote & Self.voteMask + + conviction = Conviction(rawValue: rawConviction) ?? .unknown + } + } + + struct AccountVoteStandard: Decodable { + let vote: Vote + @StringCodable var balance: BigUInt + } + + struct AccountVoteSplit: Decodable { + @StringCodable var aye: BigUInt + @StringCodable var nay: BigUInt + } + + enum AccountVote: Decodable { + case unknown + + /// A standard vote, one-way (approve or reject) with a given amount of conviction. + case standard(_ vote: AccountVoteStandard) + + /** + * A split vote with balances given for both ways, and with no conviction, useful for + * parachains when voting. + */ + case split(_ vote: AccountVoteSplit) + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "Standard": + let vote = try container.decode(AccountVoteStandard.self) + self = .standard(vote) + case "Split": + let vote = try container.decode(AccountVoteSplit.self) + self = .split(vote) + default: + self = .unknown + } + } + } + + struct Delegations: Decodable { + /// The number of votes (this is post-conviction). + @StringCodable var votes: BigUInt + + /// The amount of raw capital, used for the support. + @StringCodable var capital: BigUInt + } + + struct PriorLock: Decodable { + enum CodingKeys: String, CodingKey { + case unlockAt = "0" + case amount = "1" + } + + @StringCodable var unlockAt: BlockNumber + @StringCodable var amount: BigUInt + } + + struct CastingVotes: Decodable { + let pollIndex: PollIndex + let accountVote: AccountVote + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + + pollIndex = try container.decode(StringScaleMapper.self).value + accountVote = try container.decode(AccountVote.self) + } + } + + struct Casting: Decodable { + /// The current votes of the account + let votes: [CastingVotes] + + /// The total amount of delegations that this account has received, post-conviction-weighting + let delegations: Delegations + + /// Any pre-existing locks from past voting/delegating activity. + let prior: PriorLock + } + + struct Delegating: Decodable { + /// The amount of balance delegated. + @StringCodable var balance: BigUInt + + /// The account to which the voting power is delegated. + let target: AccountId + + /** + * The conviction with which the voting power is delegated. When this gets undelegated, the + * relevant lock begins. + */ + let conviction: Conviction + + /// The total amount of delegations that this account has received, post-conviction-weighting. + let delegations: Delegations + + /// Any pre-existing locks from past voting/delegating activity. + let prior: PriorLock + } + + enum Voting: Decodable { + case unknown + case casting(_ voting: Casting) + case delegating(_ voting: Delegating) + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "Casting": + let voting = try container.decode(Casting.self) + self = .casting(voting) + case "Delegating": + let voting = try container.decode(Delegating.self) + self = .delegating(voting) + default: + self = .unknown + } + } + } +} diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingForKey.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingForKey.swift new file mode 100644 index 0000000000..a6a79c7987 --- /dev/null +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingForKey.swift @@ -0,0 +1,23 @@ +import Foundation +import SubstrateSdk + +extension ConvictionVoting { + struct VotingForKey: JSONListConvertible, Hashable { + let accountId: AccountId + let trackId: Referenda.TrackId + + init(jsonList: [JSON], context: [CodingUserInfoKey: Any]?) throws { + let expectedFieldsCount = 2 + let actualFieldsCount = jsonList.count + guard expectedFieldsCount == actualFieldsCount else { + throw JSONListConvertibleError.unexpectedNumberOfItems( + expected: expectedFieldsCount, + actual: actualFieldsCount + ) + } + + accountId = try jsonList[0].map(to: AccountId.self, with: context) + trackId = try jsonList[1].map(to: StringScaleMapper.self, with: context).value + } + } +} diff --git a/novawalletIntegrationTests/ConvictionVotesFetchTests.swift b/novawalletIntegrationTests/ConvictionVotesFetchTests.swift new file mode 100644 index 0000000000..cea66481af --- /dev/null +++ b/novawalletIntegrationTests/ConvictionVotesFetchTests.swift @@ -0,0 +1,60 @@ +import XCTest +@testable import novawallet +import SubstrateSdk +import RobinHood + +class ConvictionVotesFetchTests: XCTestCase { + func testConvictionVoting() throws { + // given + + let storageFacade = SubstrateStorageTestFacade() + let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) + let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" + let accountId = try "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY".toAccountId() + let operationQueue = OperationQueue() + + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + guard let connection = chainRegistry.getConnection(for: chainId) else { + XCTFail("Can't get connection for chain id \(chainId)") + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + XCTFail("Can't get runtime provider for chain id \(chainId)") + return + } + + // when + + let request = MapRemoteStorageRequest(storagePath: ConvictionVoting.votingFor) { + BytesCodable(wrappedValue: accountId) + } + + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let wrapper: CompoundOperationWrapper<[ConvictionVoting.VotingForKey: ConvictionVoting.Voting]> = + requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: ConvictionVoting.votingFor, + factory: { try codingFactoryOperation.extractNoCancellableResultData() } + ) + + wrapper.addDependency(operations: [codingFactoryOperation]) + + operationQueue.addOperations([codingFactoryOperation] + wrapper.allOperations, waitUntilFinished: true) + + // then + + do { + let voting = try wrapper.targetOperation.extractNoCancellableResultData() + Logger.shared.info("Did receive voting: \(voting)") + } catch { + XCTFail("Unexpected error: \(error)") + } + } +} From 70f425955757d9ba6074eeb9b7e20bfceb32d7b8 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 28 Sep 2022 17:20:47 +0500 Subject: [PATCH 004/229] fetch voting locks --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../ConvictionVotingLocks.swift | 17 ++++++ .../ConvictionVotesFetchTests.swift | 55 ++++++++++++++++++- 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingLocks.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 04c32b5bb3..0a0ef3226f 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -789,6 +789,7 @@ 8446F5F6281916D300B7A86C /* StakingRewardsHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8446F5F5281916D300B7A86C /* StakingRewardsHeaderCell.swift */; }; 8446F5F82819235B00B7A86C /* AssetIconView+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8446F5F72819235B00B7A86C /* AssetIconView+Style.swift */; }; 8446F5FA28192FF500B7A86C /* ListLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8446F5F928192FF500B7A86C /* ListLoadingView.swift */; }; + 8448148128E46881007F64FF /* ConvictionVotingLocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8448148028E46881007F64FF /* ConvictionVotingLocks.swift */; }; 8448221826B1624E007F4492 /* SelectValidatorsConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8448221726B1624E007F4492 /* SelectValidatorsConfirmViewLayout.swift */; }; 8448221C26B1850D007F4492 /* TitleIconViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8448221B26B1850D007F4492 /* TitleIconViewModel.swift */; }; 8448336727FAAF780077FB55 /* TransakProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8448336627FAAF780077FB55 /* TransakProvider.swift */; }; @@ -3548,6 +3549,7 @@ 8446F5F5281916D300B7A86C /* StakingRewardsHeaderCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingRewardsHeaderCell.swift; sourceTree = ""; }; 8446F5F72819235B00B7A86C /* AssetIconView+Style.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AssetIconView+Style.swift"; sourceTree = ""; }; 8446F5F928192FF500B7A86C /* ListLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLoadingView.swift; sourceTree = ""; }; + 8448148028E46881007F64FF /* ConvictionVotingLocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvictionVotingLocks.swift; sourceTree = ""; }; 8448221726B1624E007F4492 /* SelectValidatorsConfirmViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmViewLayout.swift; sourceTree = ""; }; 8448221B26B1850D007F4492 /* TitleIconViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleIconViewModel.swift; sourceTree = ""; }; 8448336627FAAF780077FB55 /* TransakProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransakProvider.swift; sourceTree = ""; }; @@ -8341,6 +8343,7 @@ 848CC94528D9FC46009EB4B0 /* ConvictionVotingTally.swift */, 84532D5C28E41D8500EF4ADC /* ConvictionVoting+StoragePath.swift */, 84532D6028E4234700EF4ADC /* ConvictionVotingForKey.swift */, + 8448148028E46881007F64FF /* ConvictionVotingLocks.swift */, ); path = ConvictionVoting; sourceTree = ""; @@ -15452,6 +15455,7 @@ 8487583327F06AF300495306 /* QRScannerViewLayout.swift in Sources */, 8448336727FAAF780077FB55 /* TransakProvider.swift in Sources */, 84CFF1E326526FBC00DB7CF7 /* StakingBondMoreProtocols.swift in Sources */, + 8448148128E46881007F64FF /* ConvictionVotingLocks.swift in Sources */, 5FE687B860FC10AB08518A6E /* WalletHistoryFilterPresenter.swift in Sources */, 640A79BD1335394818E70366 /* WalletHistoryFilterViewController.swift in Sources */, DD090C2ED91726FF7779F6C7 /* WalletHistoryFilterViewFactory.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingLocks.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingLocks.swift new file mode 100644 index 0000000000..8b855ef6f9 --- /dev/null +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingLocks.swift @@ -0,0 +1,17 @@ +import Foundation +import BigInt +import SubstrateSdk + +extension ConvictionVoting { + struct ClassLock: Decodable { + let trackId: Referenda.TrackId + let amount: BigUInt + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + + trackId = try container.decode(StringScaleMapper.self).value + amount = try container.decode(StringScaleMapper.self).value + } + } +} diff --git a/novawalletIntegrationTests/ConvictionVotesFetchTests.swift b/novawalletIntegrationTests/ConvictionVotesFetchTests.swift index cea66481af..b218e34243 100644 --- a/novawalletIntegrationTests/ConvictionVotesFetchTests.swift +++ b/novawalletIntegrationTests/ConvictionVotesFetchTests.swift @@ -4,7 +4,7 @@ import SubstrateSdk import RobinHood class ConvictionVotesFetchTests: XCTestCase { - func testConvictionVoting() throws { + func testConvictionVotesFetch() throws { // given let storageFacade = SubstrateStorageTestFacade() @@ -57,4 +57,57 @@ class ConvictionVotesFetchTests: XCTestCase { XCTFail("Unexpected error: \(error)") } } + + func testConvictionLocksFetch() throws { + // given + + let storageFacade = SubstrateStorageTestFacade() + let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) + let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" + let accountId = try "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY".toAccountId() + let operationQueue = OperationQueue() + + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + guard let connection = chainRegistry.getConnection(for: chainId) else { + XCTFail("Can't get connection for chain id \(chainId)") + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + XCTFail("Can't get runtime provider for chain id \(chainId)") + return + } + + // when + + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let wrapper: CompoundOperationWrapper<[StorageResponse<[ConvictionVoting.ClassLock]>]> = + requestFactory.queryItems( + engine: connection, + keyParams: { + [BytesCodable(wrappedValue: accountId)] + }, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: ConvictionVoting.trackLocksFor + ) + + wrapper.addDependency(operations: [codingFactoryOperation]) + + operationQueue.addOperations([codingFactoryOperation] + wrapper.allOperations, waitUntilFinished: true) + + // then + + do { + let locks = try wrapper.targetOperation.extractNoCancellableResultData() + + Logger.shared.info("Did receive locks: \(locks)") + } catch { + XCTFail("Unexpected error: \(error)") + } + } } From 66898de7d55605a51ea556df2606201decfe4371 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 29 Sep 2022 16:55:46 +0500 Subject: [PATCH 005/229] fix info --- .../Common/Substrate/Types/Referenda/ReferendumInfo.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift index c0ff6f2834..6ae9b4973c 100644 --- a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift @@ -13,7 +13,7 @@ enum ReferendumInfo: Decodable { let enactment: OnChainScheduler.DispatchTime @StringCodable var submitted: Moment let decisionDeposit: Referenda.Deposit? - let desiding: DecidingStatus? + let deciding: DecidingStatus? let tally: ConvictionVoting.Tally let inQueue: Bool } From e84e48f0155375105f1871a03caa24ab4b22af79 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 30 Sep 2022 00:53:37 +0500 Subject: [PATCH 006/229] add custom segmented control --- novawallet.xcodeproj/project.pbxproj | 4 + .../colorBlack48.colorset/Contents.json | 20 ++ .../Common/View/RoundedSegmentedControl.swift | 271 ++++++++++++++++++ .../View/CrowdloanTableHeaderView.swift | 19 +- 4 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 novawallet/Assets.xcassets/colorBlack48.colorset/Contents.json create mode 100644 novawallet/Common/View/RoundedSegmentedControl.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 55e13b300f..f5df8381b2 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -972,6 +972,7 @@ 8467FD5824EFD5C2005D486C /* CDAccountItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8467FD5724EFD5C2005D486C /* CDAccountItem+CoreDataDecodable.swift */; }; 8467FD5C24EFDCC9005D486C /* UserDataStorageTestFacade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8467FD5B24EFDCC9005D486C /* UserDataStorageTestFacade.swift */; }; 846802A3265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846802A2265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift */; }; + 8468119428E6234B00BF54F1 /* RoundedSegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468119328E6234B00BF54F1 /* RoundedSegmentedControl.swift */; }; 8468B86524F59D1D00B76BC6 /* IconTitleHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468B86424F59D1D00B76BC6 /* IconTitleHeaderView.swift */; }; 8468B86A24F63CBA00B76BC6 /* AddAccount+AccountImportInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468B86924F63CBA00B76BC6 /* AddAccount+AccountImportInteractor.swift */; }; 8468B86C24F63CEF00B76BC6 /* AddAccount+AccountConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468B86B24F63CEF00B76BC6 /* AddAccount+AccountConfirmInteractor.swift */; }; @@ -3734,6 +3735,7 @@ 8467FD5724EFD5C2005D486C /* CDAccountItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDAccountItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8467FD5B24EFDCC9005D486C /* UserDataStorageTestFacade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDataStorageTestFacade.swift; sourceTree = ""; }; 846802A2265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupViewModel.swift; sourceTree = ""; }; + 8468119328E6234B00BF54F1 /* RoundedSegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedSegmentedControl.swift; sourceTree = ""; }; 8468B86424F59D1D00B76BC6 /* IconTitleHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconTitleHeaderView.swift; sourceTree = ""; }; 8468B86924F63CBA00B76BC6 /* AddAccount+AccountImportInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AddAccount+AccountImportInteractor.swift"; sourceTree = ""; }; 8468B86B24F63CEF00B76BC6 /* AddAccount+AccountConfirmInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AddAccount+AccountConfirmInteractor.swift"; sourceTree = ""; }; @@ -9112,6 +9114,7 @@ 8887813D28B7AA3100E7290F /* RoundedIconTitleCollectionHeaderView.swift */, 8887813F28B7AAB700E7290F /* RoundedIconTitleView.swift */, 84E90BA028D0B51000529633 /* CheckboxControlView.swift */, + 8468119328E6234B00BF54F1 /* RoundedSegmentedControl.swift */, ); path = View; sourceTree = ""; @@ -15479,6 +15482,7 @@ 8473F4B8282BFFF8007CC55A /* StakingRelaychainInteractor+Subscription.swift in Sources */, 841E2E5027381B2A00F250C1 /* AccountInfoSubscriptionHandlingFactory.swift in Sources */, 88AC186128CA3EE100892A9B /* LocksViewLayout.swift in Sources */, + 8468119428E6234B00BF54F1 /* RoundedSegmentedControl.swift in Sources */, A32E1373E3671D518FFC3BC2 /* YourValidatorListViewController.swift in Sources */, 84D2F1A927744C280040C680 /* PolkadotExtensionError.swift in Sources */, 37E1E9782B9752BC50AF2476 /* YourValidatorListViewFactory.swift in Sources */, diff --git a/novawallet/Assets.xcassets/colorBlack48.colorset/Contents.json b/novawallet/Assets.xcassets/colorBlack48.colorset/Contents.json new file mode 100644 index 0000000000..fb08a6620b --- /dev/null +++ b/novawallet/Assets.xcassets/colorBlack48.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.480", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Common/View/RoundedSegmentedControl.swift b/novawallet/Common/View/RoundedSegmentedControl.swift new file mode 100644 index 0000000000..6894578963 --- /dev/null +++ b/novawallet/Common/View/RoundedSegmentedControl.swift @@ -0,0 +1,271 @@ +import UIKit +import SoraUI + +class RoundedSegmentedControl: UIControl { + private enum Constants { + static let selectionAnimationKey = "selectionAnimationKey" + } + + var titles: [String] = ["Segment1", "Segment2"] { + didSet { + if oldValue.count != titles.count { + _selectedSegmentIndex = titles.count > 0 ? 0 : -1 + } + + clearSegments() + buildSegments() + + setNeedsLayout() + } + } + + var selectedSegmentIndex: Int { + get { + _selectedSegmentIndex + } + + set { + _selectedSegmentIndex = newValue + updateSelectionLayerFrame() + updateSegmentsSelection() + } + } + + var numberOfSegments: Int { + titles.count + } + + var titleColor: UIColor = .black { + didSet { + updateSegmentsSelection() + } + } + + var selectedTitleColor: UIColor = .white { + didSet { + if _selectedSegmentIndex >= 0 { + segments[_selectedSegmentIndex].textColor = selectedTitleColor + } + } + } + + var titleFont: UIFont? { + didSet { + segments.forEach { $0.font = titleFont } + } + } + + var selectionColor: UIColor = .white { + didSet { + applySelectionColor() + } + } + + var selectionCornerRadius: CGFloat = 10.0 { + didSet { + applySelectionPath() + } + } + + var contentInsets: UIEdgeInsets = .init(top: 4.0, left: 4.0, bottom: 4.0, right: 4.0) + + var selectionAnimationDuration: TimeInterval = 0.2 + + var selectionTimingOption: CAMediaTimingFunctionName = .linear + + var layoutStrategy: ListViewLayoutStrategyProtocol = HorizontalEqualWidthLayoutStrategy() { + didSet { + setNeedsLayout() + } + } + + let backgroundView: RoundedView = { + let view = RoundedView() + view.shadowOpacity = 0 + view.fillColor = .gray + view.cornerRadius = 12.0 + return view + }() + + private var _selectedSegmentIndex: Int = 0 + private var segments: [UILabel] = [] + private var selectionLayer = CAShapeLayer() + + private var selectionContentSize: CGSize { + CGSize( + width: max(bounds.width - contentInsets.left - contentInsets.right, 0), + height: max(bounds.height - contentInsets.top - contentInsets.bottom, 0) + ) + } + + private var selectedTitleLabel: UILabel? { + selectedSegmentIndex >= 0 ? segments[selectedSegmentIndex] : nil + } + + // MARK: Overriden initializers + + override public init(frame: CGRect) { + super.init(frame: frame) + configure() + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + configure() + } + + func configure() { + backgroundColor = UIColor.clear + + addSubview(backgroundView) + + buildSegments() + configureSelectionLayer() + } + + private func configureSelectionLayer() { + layer.addSublayer(selectionLayer) + + applySelectionColor() + applySelectionPath() + updateSelectionLayerFrame() + } + + // MARK: Layout + + override func layoutSubviews() { + super.layoutSubviews() + + backgroundView.frame = CGRect(x: bounds.minX, y: bounds.minY, width: bounds.width, height: bounds.height) + + let contentFrame = CGRect( + x: contentInsets.left, + y: contentInsets.top, + width: bounds.width - contentInsets.left - contentInsets.right, + height: bounds.height - contentInsets.top - contentInsets.bottom + ) + + layoutStrategy.layout(views: segments, in: contentFrame) + + applySelectionPath() + updateSelectionLayerFrame() + } + + // MARK: Segments Management + + private func buildSegments() { + guard !titles.isEmpty else { + return + } + + for (index, title) in titles.enumerated() { + let segmentLabel = UILabel() + segmentLabel.backgroundColor = .clear + segmentLabel.textAlignment = .center + segmentLabel.text = title + segmentLabel.isUserInteractionEnabled = true + addSubview(segmentLabel) + + applyStyle(for: segmentLabel, at: index) + + segments.append(segmentLabel) + + let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapSegment(_:))) + segmentLabel.addGestureRecognizer(tapRecognizer) + } + } + + private func clearSegments() { + segments.forEach { $0.removeFromSuperview() } + segments.removeAll() + } + + private func applyStyle(for segmentLabel: UILabel, at index: Int) { + segmentLabel.textColor = index == _selectedSegmentIndex ? selectedTitleColor : titleColor + segmentLabel.font = titleFont + } + + // MARK: Selection Management + + private func applySelectionColor() { + selectionLayer.fillColor = selectionColor.cgColor + } + + private func applySelectionPath() { + guard let width = selectedTitleLabel?.frame.size.width else { + return + } + + let rect = CGRect(x: 0, y: 0, width: width, height: selectionContentSize.height) + let selectionPath = UIBezierPath(roundedRect: rect, cornerRadius: selectionCornerRadius) + + selectionLayer.path = selectionPath.cgPath + } + + private func updateSelectionLayerFrame() { + guard let titleLabel = selectedTitleLabel else { + return + } + + selectionLayer.frame = CGRect( + x: titleLabel.frame.origin.x, + y: contentInsets.top, + width: titleLabel.frame.size.width, + height: selectionContentSize.height + ) + } + + private func updateSegmentsSelection() { + for (index, label) in segments.enumerated() { + label.textColor = index == _selectedSegmentIndex ? selectedTitleColor : titleColor + } + } + + private func animateSelectionIndexChange(_ fromIndex: Int) { + selectionLayer.removeAnimation(forKey: Constants.selectionAnimationKey) + + let previousLabel = segments[fromIndex] + + guard let titleLabel = selectedTitleLabel else { + return + } + + let oldFrame = CGRect( + x: previousLabel.frame.origin.x, + y: contentInsets.top, + width: previousLabel.frame.size.width, + height: selectionContentSize.height + ) + + let newFrame = CGRect( + x: titleLabel.frame.origin.x, + y: contentInsets.top, + width: titleLabel.frame.size.width, + height: selectionContentSize.height + ) + + let animation = CABasicAnimation(keyPath: "frame") + animation.fromValue = oldFrame + animation.toValue = newFrame + animation.duration = selectionAnimationDuration + animation.timingFunction = CAMediaTimingFunction(name: selectionTimingOption) + + selectionLayer.frame = newFrame + + selectionLayer.add(animation, forKey: Constants.selectionAnimationKey) + } + + // MARK: Action Handlers + + @objc private func didTapSegment(_ tapRecognizer: UITapGestureRecognizer) { + if let newIndex = segments.firstIndex(where: { $0 === tapRecognizer.view }), _selectedSegmentIndex != newIndex { + let oldIndex = _selectedSegmentIndex + _selectedSegmentIndex = newIndex + + animateSelectionIndexChange(oldIndex) + updateSegmentsSelection() + + sendActions(for: .valueChanged) + } + } +} diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift b/novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift index 0acf8964f9..2e974e47e6 100644 --- a/novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift +++ b/novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift @@ -1,4 +1,5 @@ import UIKit +import SoraUI final class CrowdloanTableHeaderView: UIView { let titleLabel: UILabel = { @@ -10,6 +11,15 @@ final class CrowdloanTableHeaderView: UIView { let walletSwitch = WalletSwitchControl() + let votingTypeSwitch: RoundedSegmentedControl = .create { view in + view.titles = ["Governance", "Crowdloans"] + view.backgroundView.fillColor = R.color.colorBlack48()! + view.selectionColor = R.color.colorWhite16()! + view.titleFont = .regularFootnote + view.selectedTitleColor = R.color.colorWhite()! + view.titleColor = R.color.colorTransparentText()! + } + let chainSelectionView: DetailsTriangularedView = { let view = UIFactory.default.createChainAssetSelectionView() return view @@ -61,10 +71,17 @@ final class CrowdloanTableHeaderView: UIView { make.centerY.equalTo(walletSwitch) } + addSubview(votingTypeSwitch) + votingTypeSwitch.snp.makeConstraints { make in + make.top.equalTo(walletSwitch.snp.bottom).offset(16) + make.leading.trailing.equalToSuperview().inset(16) + make.height.equalTo(40.0) + } + let chainBlur = TriangularedBlurView() addSubview(chainBlur) chainBlur.snp.makeConstraints { make in - make.top.equalTo(walletSwitch.snp.bottom).offset(16) + make.top.equalTo(votingTypeSwitch.snp.bottom).offset(8) make.leading.trailing.equalToSuperview().inset(16) make.bottom.equalToSuperview().inset(8) } From 57ce1a7f24425aff6a24c4d887539cab9e73fb3b Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 2 Oct 2022 22:33:04 +0500 Subject: [PATCH 007/229] add vote screen --- novawallet.xcodeproj/project.pbxproj | 80 ++++- .../iconTabCrowloan.pdf | Bin 13805 -> 0 bytes .../iconTabCrowloanFilled.pdf | Bin 3683 -> 0 bytes .../Contents.json | 2 +- .../iconTabVote.imageset/iconTabVote.pdf | Bin 0 -> 7425 bytes .../Contents.json | 5 +- .../iconTabFilled.pdf | Bin 0 -> 3909 bytes .../CrowdloanListViewController.swift | 291 ------------------ .../MainTabBar/MainTabBarViewFactory.swift | 12 +- .../CrowdloanContributionInteractor.swift | 0 .../CrowdloanContributionProtocols.swift | 0 ...rowdloanContributionViewModelFactory.swift | 0 .../CrowdloanContributionConfirmData.swift | 0 ...owdloanContributionConfirmInteractor.swift | 0 ...rowdloanContributionConfirmPresenter.swift | 0 ...rowdloanContributionConfirmProtocols.swift | 0 ...oanContributionConfirmViewController.swift | 0 ...wdloanContributionConfirmViewFactory.swift | 0 ...owdloanContributionConfirmViewLayout.swift | 0 ...rowdloanContributionConfirmWireframe.swift | 0 .../CrowdloanContributeConfirmViewModel.swift | 0 ...CrowdloanContributionSetupInteractor.swift | 0 .../CrowdloanContributionSetupPresenter.swift | 0 .../CrowdloanContributionSetupProtocols.swift | 0 ...dloanContributionSetupViewController.swift | 0 ...rowdloanContributionSetupViewFactory.swift | 0 ...CrowdloanContributionSetupViewLayout.swift | 0 .../CrowdloanContributionSetupWireframe.swift | 0 .../CrowdloanContributionSetupViewModel.swift | 0 .../BalanceViewModelFactoryFacade.swift | 0 .../CrowdloanListInteractor.swift | 1 - .../CrowdloanListPresenter.swift | 88 +++--- .../CrowdloanListProtocols.swift | 13 +- .../CrowdloanListViewFactory.swift | 0 .../CrowdloanListViewLayout.swift | 0 .../CrowdloanListViewManager.swift | 192 ++++++++++++ .../CrowdloanListWireframe.swift | 4 +- .../CrowdloanList/CrowdloansCalculator.swift | 0 .../CrowdloansListInteractor+Protocols.swift | 0 .../View/AboutCrowdloansView.swift | 0 .../View/CrowdloanEmptyView.swift | 0 .../View/CrowdloanStatusSectionView.swift | 0 .../View/CrowdloanTableHeaderView.swift | 38 ++- .../View/CrowdloanTableViewCell.swift | 0 .../View/YourContributionsView.swift | 0 .../ViewModel/CrowdloansChainViewModel.swift | 0 .../ViewModel/CrowdloansViewInfo.swift | 0 .../ViewModel/CrowdloansViewModel.swift | 0 .../CrowdloansViewModelFactory.swift | 0 ...CrowdloanYourContributionsInteractor.swift | 0 .../CrowdloanYourContributionsPresenter.swift | 0 .../CrowdloanYourContributionsProtocols.swift | 0 ...dloanYourContributionsViewController.swift | 0 ...rowdloanYourContributionsViewFactory.swift | 0 .../CrowdloanYourContributionsWireframe.swift | 0 .../View/CrowdloanYourContributionsCell.swift | 0 .../CrowdloanYourContributionsTotalCell.swift | 0 ...CrowdloanYourContributionsViewLayout.swift | 0 .../CrowdloanContributionViewModel.swift | 0 .../CrowdloanYourContributionsVMFactory.swift | 0 .../CrowdloanYourContributionsViewModel.swift | 0 .../FormattedReturnInIntervalsViewModel.swift | 0 .../ReturnInIntervalsViewModel.swift | 0 .../Acala/AcalaBonusService.swift | 0 .../CustomCrowdloan/Acala/AcalaKeys.swift | 0 .../Acala/AcalaStatementData.swift | 0 .../Acala/AcalaTransferRequest.swift | 0 .../AcalaContributionConfirmPresenter.swift | 0 .../AcalaContributionConfirmProtocols.swift | 0 .../AcalaContributionConfirmVC.swift | 0 .../AcalaContributionConfirmViewFactory.swift | 0 .../AcalaContributionSetupPresenter.swift | 0 .../AcalaContributionSetupProtocols.swift | 0 ...AcalaContributionSetupViewController.swift | 0 .../AcalaContributionSetupViewFactory.swift | 0 .../AcalaContributionSetupViewLayout.swift | 0 .../AcalaContributionSetupWireframe.swift | 0 .../Model/AcalaContributionMethod.swift | 0 .../Astar/AstarBonusService.swift | 0 .../Astar/AstarBonusServiceError.swift | 0 .../Bifrost/BifrostBonusService.swift | 0 .../CrowdloanBonusService.swift | 0 .../CrowdloanBonusServiceError.swift | 0 .../CustomCrowdloanDelegate.swift | 0 .../Karura/KaruraBonusService.swift | 0 .../Karura/KaruraResultData.swift | 0 .../Karura/KaruraStatementData.swift | 0 .../Karura/KaruraVerifyInfo.swift | 0 .../Coordinator/MoonbeamCoordinator.swift | 0 .../MoonbeamFlowCoordinatorFactory.swift | 0 .../Moonbeam/MoonbeamBonusService.swift | 0 .../Moonbeam/MoonbeamKeys.swift | 0 .../MoonbeamTermsInteractor.swift | 0 .../MoonbeamTermsPresenter.swift | 0 .../MoonbeamTermsProtocols.swift | 0 .../MoonbeamTermsViewController.swift | 0 .../MoonbeamTermsViewFactory.swift | 0 .../MoonbeamTermsViewLayout.swift | 0 .../MoonbeamTermsWireframe.swift | 0 .../Network/MoonbeamAgreeRemarkRequest.swift | 0 .../Network/MoonbeamAgreeRemarkResponse.swift | 0 .../MoonbeamMakeSignatureRequest.swift | 0 .../MoonbeamMakeSignatureResponse.swift | 0 .../Network/MoonbeamVerifiedResponse.swift | 0 .../Network/MoonbeamVerifyRemarkRequest.swift | 0 .../Crowdloan/Model/Crowdloan.swift | 0 .../Model/CrowdloanContributionDict.swift | 0 .../Model/CrowdloanDisplayInfo.swift | 0 .../Crowdloan/Model/CrowdloanFlow.swift | 0 .../Crowdloan/Model/CrowdloanMetadata.swift | 0 .../Model/CrowdloanSharedState.swift | 0 .../Crowdloan/Model/CrowdloanStatus.swift | 0 .../Crowdloan/Model/ParachainLeaseInfo.swift | 0 .../CrowdloanContributionResponse.swift | 0 .../Operation/CrowdloanOperationFactory.swift | 0 .../AcalaContributionSource.swift | 0 .../AcalaLiquidContributionResponse.swift | 0 .../ExternalContribution.swift | 0 .../ExternalContributionSource.swift | 0 .../ParallelContributionResponse.swift | 0 .../ParallelContributionSource.swift | 0 .../Crowdloan/Operation/LeaseParam.swift | 0 .../Operation/UInt32+CrowdloanAccountId.swift | 0 .../Protocols/CrowdloanErrorPresentable.swift | 0 .../ReferralCrowdloanPresenter.swift | 0 .../ReferralCrowdloanProtocols.swift | 0 .../ReferralCrowdloanViewController.swift | 0 .../ReferralCrowdloanViewFactory.swift | 0 .../ReferralCrowdloanViewLayout.swift | 0 .../ReferralCrowdloanWireframe.swift | 0 .../AttributedString+Crowdloan.swift | 0 .../ReferralCrowdloanViewModel.swift | 0 .../CrowdloanDataValidatorFactory.swift | 0 .../Crowdloan/View/BlurredTableViewCell.swift | 0 .../View/CrowdloanRewardDestinationView.swift | 0 .../CrowdloanRewardDestinationVM.swift | 0 .../Referendums/ReferendumsProtocols.swift | 3 + .../Referendums/ReferendumsViewManager.swift | 27 ++ .../Parent/VoteChildPresenterFactory.swift | 131 ++++++++ .../Modules/Vote/Parent/VoteInteractor.swift | 42 +++ .../Modules/Vote/Parent/VotePresenter.swift | 81 +++++ .../Modules/Vote/Parent/VoteProtocols.swift | 45 +++ .../Vote/Parent/VoteViewController.swift | 136 ++++++++ .../Modules/Vote/Parent/VoteViewLayout.swift | 48 +++ .../Modules/Vote/Parent/VoteWireframe.swift | 5 + novawallet/en.lproj/Localizable.strings | 2 + novawallet/ru.lproj/Localizable.strings | 2 + 147 files changed, 850 insertions(+), 398 deletions(-) delete mode 100644 novawallet/Assets.xcassets/iconsTabBar/iconTabCrowloan.imageset/iconTabCrowloan.pdf delete mode 100644 novawallet/Assets.xcassets/iconsTabBar/iconTabCrowloanFilled.imageset/iconTabCrowloanFilled.pdf rename novawallet/Assets.xcassets/iconsTabBar/{iconTabCrowloanFilled.imageset => iconTabVote.imageset}/Contents.json (71%) create mode 100644 novawallet/Assets.xcassets/iconsTabBar/iconTabVote.imageset/iconTabVote.pdf rename novawallet/Assets.xcassets/iconsTabBar/{iconTabCrowloan.imageset => iconTabVoteFilled.imageset}/Contents.json (52%) create mode 100644 novawallet/Assets.xcassets/iconsTabBar/iconTabVoteFilled.imageset/iconTabFilled.pdf delete mode 100644 novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListViewController.swift rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContribution/CrowdloanContributionInteractor.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContribution/CrowdloanContributionProtocols.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContribution/CrowdloanContributionViewModelFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContribution/Model/CrowdloanContributionConfirmData.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmInteractor.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmPresenter.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmProtocols.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewController.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewLayout.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmWireframe.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionConfirm/ViewModel/CrowdloanContributeConfirmViewModel.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupInteractor.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupPresenter.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupProtocols.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewController.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewLayout.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupWireframe.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanContributionSetup/ViewModel/CrowdloanContributionSetupViewModel.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/BalanceViewModelFactoryFacade.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift (99%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift (94%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift (80%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/CrowdloanListViewFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/CrowdloanListViewLayout.swift (100%) create mode 100644 novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift (96%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/CrowdloansCalculator.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/View/AboutCrowdloansView.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/View/CrowdloanEmptyView.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/View/CrowdloanStatusSectionView.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift (97%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/View/CrowdloanTableViewCell.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/View/YourContributionsView.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/ViewModel/CrowdloansChainViewModel.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewInfo.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModel.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModelFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsInteractor.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsPresenter.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsProtocols.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewController.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsWireframe.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsCell.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsTotalCell.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsViewLayout.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanContributionViewModel.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsVMFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsViewModel.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/ViewModel/FormattedReturnInIntervalsViewModel.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CrowdloanYourContributions/ViewModel/ReturnInIntervalsViewModel.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/AcalaBonusService.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/AcalaKeys.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/AcalaStatementData.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/AcalaTransferRequest.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmPresenter.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmProtocols.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmVC.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmViewFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupPresenter.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupProtocols.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewController.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewLayout.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupWireframe.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/Model/AcalaContributionMethod.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Astar/AstarBonusService.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Astar/AstarBonusServiceError.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Bifrost/BifrostBonusService.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/CrowdloanBonusService.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/CrowdloanBonusServiceError.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/CustomCrowdloanDelegate.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Karura/KaruraBonusService.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Karura/KaruraResultData.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Karura/KaruraStatementData.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Karura/KaruraVerifyInfo.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamCoordinator.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamFlowCoordinatorFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamBonusService.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamKeys.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsInteractor.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsPresenter.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsProtocols.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewController.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewLayout.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsWireframe.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkRequest.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkResponse.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureRequest.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureResponse.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifiedResponse.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifyRemarkRequest.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Model/Crowdloan.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Model/CrowdloanContributionDict.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Model/CrowdloanDisplayInfo.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Model/CrowdloanFlow.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Model/CrowdloanMetadata.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Model/CrowdloanSharedState.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Model/CrowdloanStatus.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Model/ParachainLeaseInfo.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/CrowdloanContributionResponse.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/CrowdloanOperationFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/ExternalContibution/AcalaContributionSource.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/ExternalContibution/AcalaLiquidContributionResponse.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/ExternalContibution/ExternalContribution.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/ExternalContibution/ExternalContributionSource.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/ExternalContibution/ParallelContributionResponse.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/ExternalContibution/ParallelContributionSource.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/LeaseParam.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Operation/UInt32+CrowdloanAccountId.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Protocols/CrowdloanErrorPresentable.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/ReferralCrowdloan/ReferralCrowdloanPresenter.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/ReferralCrowdloan/ReferralCrowdloanProtocols.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewController.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewLayout.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/ReferralCrowdloan/ReferralCrowdloanWireframe.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/ReferralCrowdloan/ViewModel/AttributedString+Crowdloan.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/ReferralCrowdloan/ViewModel/ReferralCrowdloanViewModel.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/Validation/CrowdloanDataValidatorFactory.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/View/BlurredTableViewCell.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/View/CrowdloanRewardDestinationView.swift (100%) rename novawallet/Modules/{ => Vote}/Crowdloan/ViewModel/CrowdloanRewardDestinationVM.swift (100%) create mode 100644 novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift create mode 100644 novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift create mode 100644 novawallet/Modules/Vote/Parent/VoteInteractor.swift create mode 100644 novawallet/Modules/Vote/Parent/VotePresenter.swift create mode 100644 novawallet/Modules/Vote/Parent/VoteProtocols.swift create mode 100644 novawallet/Modules/Vote/Parent/VoteViewController.swift create mode 100644 novawallet/Modules/Vote/Parent/VoteViewLayout.swift create mode 100644 novawallet/Modules/Vote/Parent/VoteWireframe.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index f5df8381b2..fcdcfcb059 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -738,6 +738,15 @@ 844138EC2830106C00AFEF6D /* ParaStkNetworkInfoViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844138EB2830106B00AFEF6D /* ParaStkNetworkInfoViewModelFactory.swift */; }; 844138EE28303A2E00AFEF6D /* ParaStkStateViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844138ED28303A2E00AFEF6D /* ParaStkStateViewModelFactory.swift */; }; 84415BCA26E783EB005A3683 /* PayoutValidatorsForNominatorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84415BC926E783EB005A3683 /* PayoutValidatorsForNominatorFactory.swift */; }; + 8442002028E6FDBE00C49C4A /* CrowdloanListViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442001F28E6FDBE00C49C4A /* CrowdloanListViewManager.swift */; }; + 8442002328E6FE1E00C49C4A /* ReferendumsViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442002228E6FE1E00C49C4A /* ReferendumsViewManager.swift */; }; + 8442002528E6FEEE00C49C4A /* ReferendumsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442002428E6FEEE00C49C4A /* ReferendumsProtocols.swift */; }; + 8442002728E6FFBA00C49C4A /* VoteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442002628E6FFBA00C49C4A /* VoteViewController.swift */; }; + 8442002928E7004B00C49C4A /* VoteViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442002828E7004B00C49C4A /* VoteViewLayout.swift */; }; + 8442002B28E9ACDB00C49C4A /* VotePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442002A28E9ACDB00C49C4A /* VotePresenter.swift */; }; + 8442002D28E9ADB500C49C4A /* VoteInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442002C28E9ADB500C49C4A /* VoteInteractor.swift */; }; + 8442002F28E9AEFB00C49C4A /* VoteWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442002E28E9AEFB00C49C4A /* VoteWireframe.swift */; }; + 8442003428E9BD3200C49C4A /* VoteChildPresenterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442003328E9BD3200C49C4A /* VoteChildPresenterFactory.swift */; }; 844384AC28538D3000611CE2 /* RewardCalculatorEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844384AB28538D3000611CE2 /* RewardCalculatorEngine.swift */; }; 844384AE28538F4700611CE2 /* UniformCurveRewardEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844384AD28538F4700611CE2 /* UniformCurveRewardEngine.swift */; }; 844384B0285391D800611CE2 /* RewardCalculatorEngineFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844384AF285391D800611CE2 /* RewardCalculatorEngineFactory.swift */; }; @@ -973,6 +982,7 @@ 8467FD5C24EFDCC9005D486C /* UserDataStorageTestFacade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8467FD5B24EFDCC9005D486C /* UserDataStorageTestFacade.swift */; }; 846802A3265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846802A2265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift */; }; 8468119428E6234B00BF54F1 /* RoundedSegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468119328E6234B00BF54F1 /* RoundedSegmentedControl.swift */; }; + 8468119728E6C90F00BF54F1 /* VoteProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468119628E6C90F00BF54F1 /* VoteProtocols.swift */; }; 8468B86524F59D1D00B76BC6 /* IconTitleHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468B86424F59D1D00B76BC6 /* IconTitleHeaderView.swift */; }; 8468B86A24F63CBA00B76BC6 /* AddAccount+AccountImportInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468B86924F63CBA00B76BC6 /* AddAccount+AccountImportInteractor.swift */; }; 8468B86C24F63CEF00B76BC6 /* AddAccount+AccountConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468B86B24F63CEF00B76BC6 /* AddAccount+AccountConfirmInteractor.swift */; }; @@ -2418,7 +2428,6 @@ BEE36A5554B026BD7BCD3199 /* StakingAmountPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40B47961B2254E8A4D8EC588 /* StakingAmountPresenter.swift */; }; BFC8C5A2C95D6EDF97D73732 /* ParaStkCollatorsSearchPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EBB92677F15F1E41762DE4 /* ParaStkCollatorsSearchPresenter.swift */; }; C01C5F1C8CB67B0D5CBE9FB1 /* StakingMainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502D42F4A480889BA226CAD3 /* StakingMainPresenter.swift */; }; - C083E2FC291784BF60EE73BA /* CrowdloanListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D852BF894D6E06EB9A92BC71 /* CrowdloanListViewController.swift */; }; C0A7710415B9C9BA496320E7 /* ParaStkYieldBoostSetupProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C2437D345C3D9B12AEE1E28 /* ParaStkYieldBoostSetupProtocols.swift */; }; C0B0DDF638915E8259B1CD67 /* StakingRedeemPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB2478DE3AF0885A3ED7ED8 /* StakingRedeemPresenter.swift */; }; C102544345E604976BF7AFFC /* LedgerNetworkSelectionWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935B5118367A118FC86B66C8 /* LedgerNetworkSelectionWireframe.swift */; }; @@ -3499,6 +3508,15 @@ 844138EB2830106B00AFEF6D /* ParaStkNetworkInfoViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParaStkNetworkInfoViewModelFactory.swift; sourceTree = ""; }; 844138ED28303A2E00AFEF6D /* ParaStkStateViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParaStkStateViewModelFactory.swift; sourceTree = ""; }; 84415BC926E783EB005A3683 /* PayoutValidatorsForNominatorFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayoutValidatorsForNominatorFactory.swift; sourceTree = ""; }; + 8442001F28E6FDBE00C49C4A /* CrowdloanListViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanListViewManager.swift; sourceTree = ""; }; + 8442002228E6FE1E00C49C4A /* ReferendumsViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsViewManager.swift; sourceTree = ""; }; + 8442002428E6FEEE00C49C4A /* ReferendumsProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsProtocols.swift; sourceTree = ""; }; + 8442002628E6FFBA00C49C4A /* VoteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteViewController.swift; sourceTree = ""; }; + 8442002828E7004B00C49C4A /* VoteViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteViewLayout.swift; sourceTree = ""; }; + 8442002A28E9ACDB00C49C4A /* VotePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VotePresenter.swift; sourceTree = ""; }; + 8442002C28E9ADB500C49C4A /* VoteInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteInteractor.swift; sourceTree = ""; }; + 8442002E28E9AEFB00C49C4A /* VoteWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteWireframe.swift; sourceTree = ""; }; + 8442003328E9BD3200C49C4A /* VoteChildPresenterFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteChildPresenterFactory.swift; sourceTree = ""; }; 844384AB28538D3000611CE2 /* RewardCalculatorEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardCalculatorEngine.swift; sourceTree = ""; }; 844384AD28538F4700611CE2 /* UniformCurveRewardEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniformCurveRewardEngine.swift; sourceTree = ""; }; 844384AF285391D800611CE2 /* RewardCalculatorEngineFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardCalculatorEngineFactory.swift; sourceTree = ""; }; @@ -3736,6 +3754,7 @@ 8467FD5B24EFDCC9005D486C /* UserDataStorageTestFacade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDataStorageTestFacade.swift; sourceTree = ""; }; 846802A2265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupViewModel.swift; sourceTree = ""; }; 8468119328E6234B00BF54F1 /* RoundedSegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedSegmentedControl.swift; sourceTree = ""; }; + 8468119628E6C90F00BF54F1 /* VoteProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteProtocols.swift; sourceTree = ""; }; 8468B86424F59D1D00B76BC6 /* IconTitleHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconTitleHeaderView.swift; sourceTree = ""; }; 8468B86924F63CBA00B76BC6 /* AddAccount+AccountImportInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AddAccount+AccountImportInteractor.swift"; sourceTree = ""; }; 8468B86B24F63CEF00B76BC6 /* AddAccount+AccountConfirmInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AddAccount+AccountConfirmInteractor.swift"; sourceTree = ""; }; @@ -5246,7 +5265,6 @@ D7A0A5EE9BE2862B085712A0 /* AssetSelectionPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetSelectionPresenter.swift; sourceTree = ""; }; D7E4D8E59F0976D412FF0B10 /* LedgerAccountConfirmationProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerAccountConfirmationProtocols.swift; sourceTree = ""; }; D7FE5F01FC9364788A91EFA5 /* SelectValidatorsConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmProtocols.swift; sourceTree = ""; }; - D852BF894D6E06EB9A92BC71 /* CrowdloanListViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanListViewController.swift; sourceTree = ""; }; D8A759A20A4A39B3B0E2A735 /* DAppAddFavoriteViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAddFavoriteViewLayout.swift; sourceTree = ""; }; D8C4C48E50DC14085258AB6D /* NftDetailsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftDetailsViewController.swift; sourceTree = ""; }; D9046DB927451ED700C29F2E /* ParallelContributionSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallelContributionSource.swift; sourceTree = ""; }; @@ -7325,6 +7343,15 @@ path = ViewModel; sourceTree = ""; }; + 8442002128E6FE0100C49C4A /* Referendums */ = { + isa = PBXGroup; + children = ( + 8442002228E6FE1E00C49C4A /* ReferendumsViewManager.swift */, + 8442002428E6FEEE00C49C4A /* ReferendumsProtocols.swift */, + ); + path = Referendums; + sourceTree = ""; + }; 8444406D28AA57D600446D22 /* Ledger */ = { isa = PBXGroup; children = ( @@ -7849,6 +7876,30 @@ path = ViewModel; sourceTree = ""; }; + 8468119528E6C87A00BF54F1 /* Vote */ = { + isa = PBXGroup; + children = ( + 8468119828E6D2A400BF54F1 /* Parent */, + 8438C486265649F800047E3F /* Crowdloan */, + 847A25C028D84A3D006AC9F5 /* Governance */, + ); + path = Vote; + sourceTree = ""; + }; + 8468119828E6D2A400BF54F1 /* Parent */ = { + isa = PBXGroup; + children = ( + 8468119628E6C90F00BF54F1 /* VoteProtocols.swift */, + 8442002628E6FFBA00C49C4A /* VoteViewController.swift */, + 8442002828E7004B00C49C4A /* VoteViewLayout.swift */, + 8442002A28E9ACDB00C49C4A /* VotePresenter.swift */, + 8442002C28E9ADB500C49C4A /* VoteInteractor.swift */, + 8442002E28E9AEFB00C49C4A /* VoteWireframe.swift */, + 8442003328E9BD3200C49C4A /* VoteChildPresenterFactory.swift */, + ); + path = Parent; + sourceTree = ""; + }; 8468B86324F59CF600B76BC6 /* TableHeader */ = { isa = PBXGroup; children = ( @@ -8164,18 +8215,11 @@ 847A25C028D84A3D006AC9F5 /* Governance */ = { isa = PBXGroup; children = ( - 847A25C128D84A48006AC9F5 /* Operation */, + 8442002128E6FE0100C49C4A /* Referendums */, ); path = Governance; sourceTree = ""; }; - 847A25C128D84A48006AC9F5 /* Operation */ = { - isa = PBXGroup; - children = ( - ); - path = Operation; - sourceTree = ""; - }; 847A25C428D84BC9006AC9F5 /* Referenda */ = { isa = PBXGroup; children = ( @@ -8555,7 +8599,7 @@ 849013D224A9268D008F705E /* Modules */ = { isa = PBXGroup; children = ( - 847A25C028D84A3D006AC9F5 /* Governance */, + 8468119528E6C87A00BF54F1 /* Vote */, 848FD1A628AE314F00CCD9E2 /* Ledger */, 8842104D289BBA8D00306F2C /* Currency */, 95ED25232B568F2C7DA953CC /* MessageSheet */, @@ -8566,7 +8610,6 @@ 846B49A92769EEC80066B875 /* DApp */, AEE0C434272A8A50009F9AD5 /* AddChainAccount */, AEE0C440272A9AD4009F9AD5 /* ImportChainAccount */, - 8438C486265649F800047E3F /* Crowdloan */, 0D927CDE29F5C9F4CA537F8F /* AccountConfirm */, 4C5888389F25B5C82454F92D /* AccountCreate */, BF6F50DD15230CADAC713359 /* AccountImport */, @@ -11656,12 +11699,12 @@ C191A3875F3255B72E01FA92 /* CrowdloanListWireframe.swift */, 86F7A369E31DCB9ABD556EE9 /* CrowdloanListPresenter.swift */, E4E78D69E8EBC3EB4D01F8EF /* CrowdloanListInteractor.swift */, - D852BF894D6E06EB9A92BC71 /* CrowdloanListViewController.swift */, 63F4BE52D0625CD8C21D2460 /* CrowdloanListViewLayout.swift */, E70C8A9C6BF8AE46CAE1CB61 /* CrowdloanListViewFactory.swift */, 84B66A0A26FDB70F0038B963 /* CrowdloansListInteractor+Protocols.swift */, 8828F4F228AD2734009E0B7C /* CrowdloansCalculator.swift */, 8828F4F428AD2763009E0B7C /* BalanceViewModelFactoryFacade.swift */, + 8442001F28E6FDBE00C49C4A /* CrowdloanListViewManager.swift */, ); path = CrowdloanList; sourceTree = ""; @@ -13832,6 +13875,7 @@ 841E6AF625EC12100007DDFE /* PreparedNomination.swift in Sources */, 848C3D0926248A3B005481C3 /* TransferCall.swift in Sources */, 843CE3A327D1FB8A00436F4E /* NftDetailsPriceView.swift in Sources */, + 8442002D28E9ADB500C49C4A /* VoteInteractor.swift in Sources */, 84D9C8F328ADA42F007FB23B /* Data+Chunk.swift in Sources */, 8456C08227CF9DC9001282DE /* RemoteNftModel.swift in Sources */, 8401AEC42642A71D000B03E3 /* StakingRebondConfirmationWireframe.swift in Sources */, @@ -13994,6 +14038,7 @@ 84EE2FAB289120AF00A98816 /* WalletManageInteractor.swift in Sources */, 842876B424AE059700D91AD8 /* SocialMessage.swift in Sources */, 849014BC24AA87E4008F705E /* PinSetupInteractor.swift in Sources */, + 8468119728E6C90F00BF54F1 /* VoteProtocols.swift in Sources */, 844B6EC728A3B05300A8BE83 /* MessageSheetViewModel.swift in Sources */, 84EE780227C4C2A40027357F /* DAppListFeaturedHeaderView.swift in Sources */, 845BB8D125E45F1300E5FCDC /* NominateCall.swift in Sources */, @@ -14307,6 +14352,7 @@ 8436EDE225895804004D9E97 /* RampProvider.swift in Sources */, 849013AC24A80984008F705E /* AppDelegate.swift in Sources */, 8476D39D27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift in Sources */, + 8442002028E6FDBE00C49C4A /* CrowdloanListViewManager.swift in Sources */, 84CE69E82566750D00559427 /* ByteLengthProcessor.swift in Sources */, 8494D87A2525350000614D8F /* SubscanStatusData.swift in Sources */, 8499FEDA27BFDB8C00712589 /* NFTStreamableSource.swift in Sources */, @@ -14345,6 +14391,7 @@ AEA0C8BA268113F900F9666F /* YourValidatorList+RecommendedList.swift in Sources */, 88421056289BBA8D00306F2C /* CurrencyPresenter.swift in Sources */, 84D33996262250B800130A89 /* String+Substrate.swift in Sources */, + 8442003428E9BD3200C49C4A /* VoteChildPresenterFactory.swift in Sources */, 843CE3A827D20A8700436F4E /* NftDetailsCollection.swift in Sources */, 841816792825A20E0007684A /* ParaStakingRewardCalculatorService.swift in Sources */, 849014FF24AB69A4008F705E /* WalletContextFactory.swift in Sources */, @@ -14432,6 +14479,7 @@ 84CD82AE263C1452001A6F01 /* SubstrateProviderSubscriber.swift in Sources */, AE6F7FE62685F2C3002BBC3E /* ValidatorListFilterViewModel.swift in Sources */, F40966F626B299FC008CD244 /* SubqueryStakeSource.swift in Sources */, + 8442002B28E9ACDB00C49C4A /* VotePresenter.swift in Sources */, 84FB1F652526879200E0242B /* WalletSingleProviderIdFactory.swift in Sources */, 84EFB78F28AB897D003B8396 /* LedgerResponse.swift in Sources */, F429C3CC272940A2000214EE /* MoonbeamVerifyRemarkRequest.swift in Sources */, @@ -14884,6 +14932,7 @@ 843612BD278FE54D00DC739E /* DAppOperationConfirmInteractor+Protocol.swift in Sources */, 844DBC5E274D1B13009F8351 /* IconWithTitleSubtitleTableViewCell.swift in Sources */, 84DBEA42265E80DD00FDF73C /* LearnMoreViewModel.swift in Sources */, + 8442002928E7004B00C49C4A /* VoteViewLayout.swift in Sources */, 84DD5F21263CB6BE00425ACF /* UnbondCall.swift in Sources */, AEF50716262359DC0098574D /* WalletSelectPurchaseProviderCommand.swift in Sources */, 2AF8204F274FD2120092E3E7 /* BaseAccountCreatePresenter.swift in Sources */, @@ -15308,6 +15357,7 @@ 84FB298C2639ABA500BE0FCD /* YourValidatorList.swift in Sources */, F4D6FF0E26B3DD6E002313AF /* AnalyticsRewardsProtocols.swift in Sources */, 84873AFF26028E2B000A83EE /* StakingStateMachine.swift in Sources */, + 8442002528E6FEEE00C49C4A /* ReferendumsProtocols.swift in Sources */, 3D1FB0EF87D42F08D9250552 /* PurchasePresenter.swift in Sources */, F4F22976260DBF3F00ACFDB8 /* StakingPayoutRewardTableCell.swift in Sources */, 8428229A289BC8E400163031 /* AddAccount+ParitySignerWelcomeWireframe.swift in Sources */, @@ -15542,6 +15592,7 @@ 84DED40B266656D400A153BB /* KaruraBonusService.swift in Sources */, 842A736627DB485E006EE1EA /* OperationSlashModel.swift in Sources */, 885551F78A5926D16D5AF0CB /* ControllerAccountPresenter.swift in Sources */, + 8442002F28E9AEFB00C49C4A /* VoteWireframe.swift in Sources */, 841E553C282D44BA00C8438F /* ParachainStakingAccountSubscriptionService.swift in Sources */, 84300B2C26C10C9B00D64514 /* ConnectionStateReporting.swift in Sources */, 9E4E458C92D12B24D5EAD893 /* ControllerAccountInteractor.swift in Sources */, @@ -15565,7 +15616,6 @@ 846CA7802709A41E0011124C /* StakingAnalyticsLocalSubscriptionHandler.swift in Sources */, 849DF02D26C40B7900B702F4 /* RuntimeFilesOperationFactory.swift in Sources */, 0B2B9C6E2BA2E924D6A54F4B /* CrowdloanListInteractor.swift in Sources */, - C083E2FC291784BF60EE73BA /* CrowdloanListViewController.swift in Sources */, 5888936B3D13D92F1534E08B /* CrowdloanListViewLayout.swift in Sources */, 849C066F2765140B00394C82 /* AnyCancellableCleaning.swift in Sources */, 8489A6D627FDA50D0040C066 /* AccountLocalStorageSubscriber.swift in Sources */, @@ -15746,6 +15796,7 @@ 37E229641DCDF64AC5AF1DCD /* DAppBrowserPresenter.swift in Sources */, 91530F7301CA39654E008580 /* DAppBrowserInteractor.swift in Sources */, DE03CA5AD7F1D0B80DFF13B6 /* DAppBrowserViewController.swift in Sources */, + 8442002328E6FE1E00C49C4A /* ReferendumsViewManager.swift in Sources */, 70C0E48EE41B4C7229F5946C /* DAppBrowserViewLayout.swift in Sources */, FDE2CA45061C620567AC329C /* DAppBrowserViewFactory.swift in Sources */, 882C29AC28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift in Sources */, @@ -15925,6 +15976,7 @@ 84EBFCEB285E7E130006327E /* XcmWeightLimit.swift in Sources */, D7B4AE688B93EC562F452F4E /* ParaStkUnstakeInteractor.swift in Sources */, 5FD7B3463822BC69AF5E3C72 /* ParaStkUnstakeViewController.swift in Sources */, + 8442002728E6FFBA00C49C4A /* VoteViewController.swift in Sources */, 3E6215E91AE1C1F78246A43C /* ParaStkUnstakeViewLayout.swift in Sources */, 790129F3CB6AEA611639E886 /* ParaStkUnstakeViewFactory.swift in Sources */, C74B44F382EDAE5CB5A8468F /* ParaStkUnstakeConfirmProtocols.swift in Sources */, diff --git a/novawallet/Assets.xcassets/iconsTabBar/iconTabCrowloan.imageset/iconTabCrowloan.pdf b/novawallet/Assets.xcassets/iconsTabBar/iconTabCrowloan.imageset/iconTabCrowloan.pdf deleted file mode 100644 index afe9a0ebbf0bc9ccf97f9012adb9c084e9074002..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13805 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 diff --git a/novawallet/Assets.xcassets/iconsTabBar/iconTabCrowloanFilled.imageset/iconTabCrowloanFilled.pdf b/novawallet/Assets.xcassets/iconsTabBar/iconTabCrowloanFilled.imageset/iconTabCrowloanFilled.pdf deleted file mode 100644 index 1a50de0606ceae90060c4831cca2667f47e73ad7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3683 zcma)CX)@>C_SfGg=bk-t&!120&4vC>;S^tdzuvsxe{d1-T&H&X z>-F+#TD)BUdAVAjfAhkfy*d52+D(5p0hH z3h31B+Cyx-4|B2}a?#0}qpt@nSqXh$zV{f$xoq7Ux2?@B#)9=B&X%*K;4IA6YL^v$ zE(w2%Yxq;q?X1o|d!IU&>)cbeh?51)(Wm6<9CI(VImU6Jq-!;$xf$|xs;5@*`s2WI!ZF#!Lm|@0?p0Prf>RayRz1ule;o;3 zDFW*u!IBD@n)S%3-YvneI_K0e%Vjv@>p)_M@3Mh>n-Mr(R+!rhHk7#+q!qAS3vMF9 zDz80Asx_gp&dK}Onvk4JJus|VZ)ITeUTN~gFK3;ChOxkB?8ErcxE?gk)%0PKcl3+MeHuY(O3{_jEE=FR&Xp2{_+YeEsmBNS zl*t$vJ)@Hqu#)L6vI&$7lQwx_#;rp;q|8V+7+uilX_A=92$3zbB8HrCTV3U*AyR)G zKa_(O)z(xPRZ+&WKp&)itDDjrX;a*$+Zl;Q4_!27(FxmN1zZzG2oo(GETbHIj~KV< zqcj=@#t{WeSV_x2kw|tZFOQs4-DM6jnxr4CEYcH12GV!qO@ZIBklQc(<_^`bm>(lV z$wwM7mLDU@xx`??p3|5kGt=aUx3}4mZfkzz_BM;y=xGAnzRUOUyW`;jrItt0Yr4c- z&>fjpB``M>3&zlaZJj4*Ic{6FstO@b%tX2v>L-stIF zgUtWEtzxB zTjL%J3q?8Z84{>TNJ=MV;Aov{>3|S2=nX}Sj)^DPWc!kRR_`; zG*Uj>3qH0e!5<*cTS%!=QrZcwwwKWgGPO~+=8!{*INChzKW@O6031dZ7N z-~4D6FAAnN2xNXyg%h|TWasmR2<2PN%Z`XPRQy}bOmzMl9DTzvbIa6H~^uhvi8 r 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 ODpu30S8xCF-Twd;o5Vc; literal 0 HcmV?d00001 diff --git a/novawallet/Assets.xcassets/iconsTabBar/iconTabCrowloan.imageset/Contents.json b/novawallet/Assets.xcassets/iconsTabBar/iconTabVoteFilled.imageset/Contents.json similarity index 52% rename from novawallet/Assets.xcassets/iconsTabBar/iconTabCrowloan.imageset/Contents.json rename to novawallet/Assets.xcassets/iconsTabBar/iconTabVoteFilled.imageset/Contents.json index c6f459a162..5a701f427d 100644 --- a/novawallet/Assets.xcassets/iconsTabBar/iconTabCrowloan.imageset/Contents.json +++ b/novawallet/Assets.xcassets/iconsTabBar/iconTabVoteFilled.imageset/Contents.json @@ -1,15 +1,12 @@ { "images" : [ { - "filename" : "iconTabCrowloan.pdf", + "filename" : "iconTabFilled.pdf", "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" } } diff --git a/novawallet/Assets.xcassets/iconsTabBar/iconTabVoteFilled.imageset/iconTabFilled.pdf b/novawallet/Assets.xcassets/iconsTabBar/iconTabVoteFilled.imageset/iconTabFilled.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e325ebffdd2146901d8538fb3f1f468385f5b307 GIT binary patch literal 3909 zcmZXX-H#l_6~*8Cuc#MGfJ9H#t#1h-fgMLtf-nnj77xpMuotao!p;(r{Pp>r>Ykoi zJeI89({-!v*EzTP#hX{JzYKGorr^9g{_@-8+*e<@ufLx5hj;pOvTJFzL@pGyoeR~OQpt@&c^qtM)P>3N{BB;VY_K$EY%4K$@*yVFYV zZN*CKabT&2P`cI?p8|W{$vP$TycZgKY+2UHO7IKTVkzZ}g@IM;v7W7235rcgF}1RI zBzvJ@wvs|Hz4w7Lo3Lh~b#tN5$>T_MX0wla#-q^Y7IH|~*laNqyaO|zW5Ak~HAEv} zb#6p!Q9Bkah#Tw5`)0;UJnFq9tc&(ZiM;i>Ws-??o}=a5lQ3Uvz#pvB97-N}Z?o?? zG_o3JpR;-Vt#j--6HSo6xwWXhd+)VGS%U#$kMtlbCInGSBzlQm(%awM7sBWqwKQslB&Yb7Y*_)?QvV_6zfa^#fsks+OJ z&1wUx9)sax57uG@$`~3QI%4THc7Z9C5=oiOA=FYcP)x-~Jf%XpsrM*Q%ZY}@G*YZa zrW_TjE!pT|iz&AbWFgWUqX3*w3zs>n03(A`D)dU{W!k9w@d@ zbRkZn`$*h1?-C7=mDPo`%ep|56Dp+`LLk}|0$1x7kcUCKTaus4s1FM!rWiSdF z+p=f&meR0p!3F`5krcZT6yin0(;DnZ9m|R(K((L9wh9(2vroCpqc8`u?xBf?5DiTc zS>a2x(a6-;muHyGsFi`S=VfJN&ya}hYR3c_d)JPavp2E4n?9hi6}8midB&m4krLi3 zkh~!U4+Bgou`;1Ou&1HRXl2ZFJ#80YYm!t~^pRvF+KEn6DV~A36VKQ$iu|M!J%K4W zd6^4T8}>Iz|2jQjQE9ExS=#RmLevUTWJ*3vYzs86T5q@#6SASaB4eW$<+ATu#}l! z3-qUGNE)j;I^H`-Exw}YHpg5VJl_yXOE31q(HlmyNTMov*)YS0ScU{aERT91#a1JO zOI(DO((Fi&1=0f6Q`a;BQTBtRF!jhRxI*Ai_Nv^5A)_KJIed5qVi<6H+n;p_hLg?B z4ItQ8=n2KNdMmJIW+9=kApt>5x*lka`~t~zP0a zZpEYXAzfqoY!wDdus7ys(8>?dhVDV4(KO8$7NQXF=7OTLgn;Ja;UE>RPY+v!^pdkWT@@f*5Q8*uOM(ZKF=U!>WCr2nM6N3kn&7o6 zF+LC;HVZV(YU+JfF3Dh|0-S&$b4IK*{>h8VosX!gE1E#l%U6Wi7)5AO-Z=y^>L zCF_E1z54JBj8>tgY#9K|WHE=%p>a6U@Ord4BwjQ$&7J!~Blm;Ep$~VNi<}PxiFK9B zNDi0caVuM)(JI_EbiLcwJy4U*=s>V8po&f=NW|p~VZC{JR@m7Y&`>GKuwK0eyRdT& z?isc+R!si&i|H`^FzJhD{hT>}`{*-g`6glzx9yXNf?qzBcHbNh$ETBf`!k(|MGt9H{<-O&kNaOI@9MO~s{b8YfW82)KaFtx++l;bg*}HN_oz=GZohw7 zC6)OL#HDkCo*r-SANG$EAG*7LydoW+osJ*(pS#cQ-+jI$Wp{HtJ~;(E61@BI{(pPC WA0NE8k540<2;-+0FaGxZ>;D7w?Gq^g literal 0 HcmV?d00001 diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListViewController.swift b/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListViewController.swift deleted file mode 100644 index 92948b3513..0000000000 --- a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListViewController.swift +++ /dev/null @@ -1,291 +0,0 @@ -import UIKit -import SoraFoundation -import SoraUI - -final class CrowdloanListViewController: UIViewController, ViewHolder { - typealias RootViewType = CrowdloanListViewLayout - - let presenter: CrowdloanListPresenterProtocol - - private var chainInfo: CrowdloansChainViewModel? - private var state: CrowdloanListState = .loading - - private var shouldUpdateOnAppearance: Bool = false - - init( - presenter: CrowdloanListPresenterProtocol, - localizationManager: LocalizationManagerProtocol - ) { - self.presenter = presenter - - super.init(nibName: nil, bundle: nil) - - self.localizationManager = localizationManager - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func loadView() { - view = CrowdloanListViewLayout() - } - - override func viewDidLoad() { - super.viewDidLoad() - - configure() - setupLocalization() - applyState() - - presenter.setup() - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - if case .loading = state { - didStartLoading() - } - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - if shouldUpdateOnAppearance { - presenter.refresh(shouldReset: false) - } else { - shouldUpdateOnAppearance = true - } - - presenter.becomeOnline() - } - - override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - - presenter.putOffline() - - if case .loading = state { - didStopLoading() - } - } - - func configure() { - rootView.tableView.registerClassForCell(YourContributionsTableViewCell.self) - rootView.tableView.registerClassForCell(AboutCrowdloansTableViewCell.self) - rootView.tableView.registerClassForCell(CrowdloanTableViewCell.self) - rootView.tableView.registerClassForCell(BlurredTableViewCell.self) - rootView.tableView.registerClassForCell(BlurredTableViewCell.self) - rootView.tableView.registerHeaderFooterView(withClass: CrowdloanStatusSectionView.self) - rootView.tableView.dataSource = self - rootView.tableView.delegate = self - - if let refreshControl = rootView.tableView.refreshControl { - refreshControl.addTarget(self, action: #selector(actionRefresh), for: .valueChanged) - } - - rootView.headerView.chainSelectionView.addTarget( - self, - action: #selector(actionSelectChain), - for: .touchUpInside - ) - - rootView.headerView.walletSwitch.addTarget( - self, - action: #selector(actionWalletSwitch), - for: .touchUpInside - ) - } - - private func setupLocalization() { - let languages = selectedLocale.rLanguages - rootView.headerView.titleLabel.text = R.string.localizable - .tabbarCrowdloanTitle_v190(preferredLanguages: languages) - } - - private func applyState() { - switch state { - case .loading: - didStartLoading() - case .loaded: - rootView.tableView.refreshControl?.endRefreshing() - didStopLoading() - } - - rootView.tableView.reloadData() - } - - @objc func actionRefresh() { - presenter.refresh(shouldReset: false) - } - - @objc func actionSelectChain() { - presenter.selectChain() - } - - @objc func actionWalletSwitch() { - presenter.handleWalletSwitch() - } -} - -extension CrowdloanListViewController: UITableViewDataSource { - func numberOfSections(in _: UITableView) -> Int { - switch state { - case let .loaded(viewModel): - return viewModel.sections.count - case .loading: - return 0 - } - } - - func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { - switch state { - case let .loaded(viewModel): - let sectionModel = viewModel.sections[section] - switch sectionModel { - case let .active(_, cellViewModels): - return cellViewModels.count - case let .completed(_, cellViewModels): - return cellViewModels.count - case .yourContributions, .about, .error, .empty: - return 1 - } - case .loading: - return 0 - } - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch state { - case let .loaded(viewModel): - let sectionModel = viewModel.sections[indexPath.section] - switch sectionModel { - case let .active(_, cellViewModels), let .completed(_, cellViewModels): - let cell = tableView.dequeueReusableCellWithType(CrowdloanTableViewCell.self)! - let cellViewModel = cellViewModels[indexPath.row] - cell.bind(viewModel: cellViewModel) - return cell - case let .yourContributions(model): - let cell = tableView.dequeueReusableCellWithType(YourContributionsTableViewCell.self)! - cell.view.bind(model: model) - return cell - case let .about(model): - let cell = tableView.dequeueReusableCellWithType(AboutCrowdloansTableViewCell.self)! - cell.view.bind(model: model) - return cell - case let .error(message): - let cell: BlurredTableViewCell = tableView.dequeueReusableCell(for: indexPath) - cell.view.errorDescriptionLabel.text = message - cell.view.delegate = self - cell.view.locale = selectedLocale - cell.applyStyle() - return cell - case .empty: - let cell: BlurredTableViewCell = tableView.dequeueReusableCell(for: indexPath) - let text = R.string.localizable - .crowdloanEmptyMessage_v3_9_1(preferredLanguages: selectedLocale.rLanguages) - cell.view.bind( - image: R.image.iconEmptyHistory(), - text: text - ) - cell.applyStyle() - return cell - } - case .loading: - return UITableViewCell() - } - } -} - -extension CrowdloanListViewController: UITableViewDelegate { - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.deselectRow(at: indexPath, animated: true) - - guard case let .loaded(viewModel) = state else { - return - } - - let sectionModel = viewModel.sections[indexPath.section] - switch sectionModel { - case let .active(_, cellViewModels): - let viewModel = cellViewModels[indexPath.row] - presenter.selectCrowdloan(viewModel.paraId) - case .yourContributions: - presenter.handleYourContributions() - default: - return - } - } - - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - guard case let .loaded(viewModel) = state else { - return nil - } - - let sectionModel = viewModel.sections[section] - switch sectionModel { - case let .active(title, cells), let .completed(title, cells): - let headerView: CrowdloanStatusSectionView = tableView.dequeueReusableHeaderFooterView() - headerView.bind(title: title, count: cells.count) - return headerView - case let .empty(title): - let headerView: CrowdloanStatusSectionView = tableView.dequeueReusableHeaderFooterView() - headerView.bind(title: title, count: 0) - return headerView - default: - return nil - } - } - - func tableView(_: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - guard case let .loaded(viewModel) = state else { - return 0.0 - } - - let sectionModel = viewModel.sections[section] - switch sectionModel { - case .active, .completed, .empty: - return UITableView.automaticDimension - default: - return 0.0 - } - } -} - -extension CrowdloanListViewController: CrowdloanListViewProtocol { - func didReceive(walletSwitchViewModel: WalletSwitchViewModel) { - rootView.headerView.walletSwitch.bind(viewModel: walletSwitchViewModel) - } - - func didReceive(chainInfo: CrowdloansChainViewModel) { - self.chainInfo = chainInfo - - rootView.headerView.bind(viewModel: chainInfo) - rootView.headerView.setNeedsLayout() - } - - func didReceive(listState: CrowdloanListState) { - state = listState - - applyState() - } -} - -extension CrowdloanListViewController: Localizable { - func applyLocalization() { - if isViewLoaded { - setupLocalization() - } - } -} - -extension CrowdloanListViewController: ErrorStateViewDelegate { - func didRetry(errorView _: ErrorStateView) { - presenter.refresh(shouldReset: true) - } -} - -extension CrowdloanListViewController: LoadableViewProtocol {} -extension CrowdloanListViewController: HiddableBarWhenPushed {} diff --git a/novawallet/Modules/MainTabBar/MainTabBarViewFactory.swift b/novawallet/Modules/MainTabBar/MainTabBarViewFactory.swift index 0568270ff2..6455caa595 100644 --- a/novawallet/Modules/MainTabBar/MainTabBarViewFactory.swift +++ b/novawallet/Modules/MainTabBar/MainTabBarViewFactory.swift @@ -33,7 +33,7 @@ final class MainTabBarViewFactory: MainTabBarViewFactoryProtocol { return nil } - guard let crowdloanController = createCrowdloanController( + guard let crowdloanController = createVoteController( for: localizationManager, state: CrowdloanSharedState() ) else { @@ -73,7 +73,7 @@ final class MainTabBarViewFactory: MainTabBarViewFactoryProtocol { static func reloadCrowdloanView(on view: MainTabBarViewProtocol) { let localizationManager = LocalizationManager.shared - guard let crowdloanController = createCrowdloanController( + guard let crowdloanController = createVoteController( for: localizationManager, state: CrowdloanSharedState() ) else { @@ -189,7 +189,7 @@ final class MainTabBarViewFactory: MainTabBarViewFactoryProtocol { return navigationController } - static func createCrowdloanController( + static func createVoteController( for localizationManager: LocalizationManagerProtocol, state: CrowdloanSharedState ) -> UIViewController? { @@ -200,12 +200,12 @@ final class MainTabBarViewFactory: MainTabBarViewFactoryProtocol { let navigationController = FearlessNavigationController(rootViewController: crowloanView.controller) let localizableTitle = LocalizableResource { locale in - R.string.localizable.tabbarCrowdloanTitle_v190(preferredLanguages: locale.rLanguages) + R.string.localizable.tabbarVoteTitle(preferredLanguages: locale.rLanguages) } let currentTitle = localizableTitle.value(for: localizationManager.selectedLocale) - let commonIconImage = R.image.iconTabCrowloan() - let selectedIconImage = R.image.iconTabCrowloanFilled() + let commonIconImage = R.image.iconTabVote() + let selectedIconImage = R.image.iconTabVoteFilled() let commonIcon = commonIconImage?.tinted(with: R.color.colorWhite()!)? .withRenderingMode(.alwaysOriginal) diff --git a/novawallet/Modules/Crowdloan/CrowdloanContribution/CrowdloanContributionInteractor.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContribution/CrowdloanContributionInteractor.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContribution/CrowdloanContributionInteractor.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContribution/CrowdloanContributionInteractor.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContribution/CrowdloanContributionProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContribution/CrowdloanContributionProtocols.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContribution/CrowdloanContributionProtocols.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContribution/CrowdloanContributionProtocols.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContribution/CrowdloanContributionViewModelFactory.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContribution/CrowdloanContributionViewModelFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContribution/CrowdloanContributionViewModelFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContribution/CrowdloanContributionViewModelFactory.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContribution/Model/CrowdloanContributionConfirmData.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContribution/Model/CrowdloanContributionConfirmData.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContribution/Model/CrowdloanContributionConfirmData.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContribution/Model/CrowdloanContributionConfirmData.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmInteractor.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmInteractor.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmInteractor.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmInteractor.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmPresenter.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmPresenter.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmPresenter.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmPresenter.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmProtocols.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmProtocols.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmProtocols.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewController.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewController.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewController.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewController.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewFactory.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewFactory.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewLayout.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewLayout.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewLayout.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmViewLayout.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmWireframe.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmWireframe.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmWireframe.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmWireframe.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/ViewModel/CrowdloanContributeConfirmViewModel.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/ViewModel/CrowdloanContributeConfirmViewModel.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionConfirm/ViewModel/CrowdloanContributeConfirmViewModel.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/ViewModel/CrowdloanContributeConfirmViewModel.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupInteractor.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupInteractor.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupInteractor.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupInteractor.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupPresenter.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupPresenter.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupPresenter.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupPresenter.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupProtocols.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupProtocols.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupProtocols.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewController.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewController.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewController.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewController.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewFactory.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewFactory.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewLayout.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewLayout.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewLayout.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupViewLayout.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupWireframe.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupWireframe.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupWireframe.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupWireframe.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanContributionSetup/ViewModel/CrowdloanContributionSetupViewModel.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/ViewModel/CrowdloanContributionSetupViewModel.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanContributionSetup/ViewModel/CrowdloanContributionSetupViewModel.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanContributionSetup/ViewModel/CrowdloanContributionSetupViewModel.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/BalanceViewModelFactoryFacade.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/BalanceViewModelFactoryFacade.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/BalanceViewModelFactoryFacade.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/BalanceViewModelFactoryFacade.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift similarity index 99% rename from novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift index d64eeff365..bce4c0a980 100644 --- a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift @@ -312,7 +312,6 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { extension CrowdloanListInteractor { func setup(with accountId: AccountId?, chain: ChainModel) { - presenter.didReceive(wallet: selectedMetaAccount) presenter.didReceiveSelectedChain(result: .success(chain)) if let accountId = accountId { diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift similarity index 94% rename from novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift index 9cce7911d1..5baf9d003b 100644 --- a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift @@ -4,12 +4,13 @@ import BigInt import SubstrateSdk final class CrowdloanListPresenter { - weak var view: CrowdloanListViewProtocol? + weak var view: CrowdloansViewProtocol? let wireframe: CrowdloanListWireframeProtocol let interactor: CrowdloanListInteractorInputProtocol let viewModelFactory: CrowdloansViewModelFactoryProtocol let logger: LoggerProtocol? let accountManagementFilter: AccountManagementFilterProtocol + let wallet: MetaAccountModel private var selectedChainResult: Result? private var accountInfoResult: Result? @@ -23,14 +24,13 @@ final class CrowdloanListPresenter { private var contributionsResult: Result? private var externalContributions: [ExternalContribution]? private var leaseInfoResult: Result? - private var wallet: MetaAccountModel? - private lazy var walletSwitchViewModelFactory = WalletSwitchViewModelFactory() private let crowdloansCalculator: CrowdloansCalculatorProtocol init( interactor: CrowdloanListInteractorInputProtocol, wireframe: CrowdloanListWireframeProtocol, + wallet: MetaAccountModel, viewModelFactory: CrowdloansViewModelFactoryProtocol, localizationManager: LocalizationManagerProtocol, crowdloansCalculator: CrowdloansCalculatorProtocol, @@ -39,6 +39,7 @@ final class CrowdloanListPresenter { ) { self.interactor = interactor self.wireframe = wireframe + self.wallet = wallet self.viewModelFactory = viewModelFactory self.logger = logger self.crowdloansCalculator = crowdloansCalculator @@ -46,19 +47,6 @@ final class CrowdloanListPresenter { self.localizationManager = localizationManager } - private func updateWalletSwitchView() { - guard let wallet = wallet else { - return - } - - let viewModel = walletSwitchViewModelFactory.createViewModel( - from: wallet.walletIdenticonData(), - walletType: wallet.type - ) - - view?.didReceive(walletSwitchViewModel: viewModel) - } - private func updateChainView() { guard let chainResult = selectedChainResult else { return @@ -219,11 +207,37 @@ final class CrowdloanListPresenter { } } -extension CrowdloanListPresenter: CrowdloanListPresenterProtocol { +extension CrowdloanListPresenter: VoteChildPresenterProtocol { func setup() { interactor.setup() } + func becomeOnline() { + interactor.becomeOnline() + } + + func putOffline() { + interactor.putOffline() + } + + func selectChain() { + guard + let chain = try? selectedChainResult?.get(), + let asset = chain.utilityAsset() else { + return + } + + let chainAssetId = ChainAsset(chain: chain, asset: asset).chainAssetId + + wireframe.selectChain( + from: view, + delegate: self, + selectedChainAssetId: chainAssetId + ) + } +} + +extension CrowdloanListPresenter: CrowdloanListPresenterProtocol { func refresh(shouldReset: Bool) { crowdloansResult = nil @@ -239,7 +253,7 @@ extension CrowdloanListPresenter: CrowdloanListPresenterProtocol { } func selectCrowdloan(_ paraId: ParaId) { - guard let wallet = wallet, let chain = try? selectedChainResult?.get() else { + guard let chain = try? selectedChainResult?.get() else { return } @@ -261,6 +275,10 @@ extension CrowdloanListPresenter: CrowdloanListPresenterProtocol { message: message, locale: selectedLocale ) { [weak self] in + guard let wallet = self?.wallet else { + return + } + self?.wireframe.showWalletDetails(from: self?.view, wallet: wallet) } } else { @@ -277,34 +295,6 @@ extension CrowdloanListPresenter: CrowdloanListPresenterProtocol { } } - func becomeOnline() { - interactor.becomeOnline() - } - - func putOffline() { - interactor.putOffline() - } - - func selectChain() { - guard - let chain = try? selectedChainResult?.get(), - let asset = chain.utilityAsset() else { - return - } - - let chainAssetId = ChainAsset(chain: chain, asset: asset).chainAssetId - - wireframe.selectChain( - from: view, - delegate: self, - selectedChainAssetId: chainAssetId - ) - } - - func handleWalletSwitch() { - wireframe.showWalletSwitch(from: view) - } - func handleYourContributions() { guard let chainResult = selectedChainResult, @@ -414,12 +404,6 @@ extension CrowdloanListPresenter: CrowdloanListInteractorOutputProtocol { updateChainView() } - func didReceive(wallet: MetaAccountModel) { - self.wallet = wallet - - updateWalletSwitchView() - } - func didReceivePriceData(result: Result?) { priceDataResult = result updateListView() diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift similarity index 80% rename from novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift index 03936e2a73..4ac0f6106a 100644 --- a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift @@ -1,20 +1,14 @@ import SoraFoundation -protocol CrowdloanListViewProtocol: ControllerBackedProtocol, AlertPresentable, LoadableViewProtocol { - func didReceive(walletSwitchViewModel: WalletSwitchViewModel) +protocol CrowdloansViewProtocol: AlertPresentable, ControllerBackedProtocol, LoadableViewProtocol { func didReceive(chainInfo: CrowdloansChainViewModel) func didReceive(listState: CrowdloanListState) } protocol CrowdloanListPresenterProtocol: AnyObject { - func setup() func refresh(shouldReset: Bool) func selectCrowdloan(_ paraId: ParaId) - func becomeOnline() - func putOffline() - func selectChain() func handleYourContributions() - func handleWalletSwitch() } protocol CrowdloanListInteractorInputProtocol: AnyObject { @@ -37,13 +31,12 @@ protocol CrowdloanListInteractorOutputProtocol: AnyObject { func didReceiveLeaseInfo(result: Result) func didReceiveSelectedChain(result: Result) func didReceiveAccountInfo(result: Result) - func didReceive(wallet: MetaAccountModel) func didReceivePriceData(result: Result?) } -protocol CrowdloanListWireframeProtocol: WalletSwitchPresentable, AlertPresentable, NoAccountSupportPresentable { +protocol CrowdloanListWireframeProtocol: AlertPresentable, NoAccountSupportPresentable { func presentContributionSetup( - from view: CrowdloanListViewProtocol?, + from view: ControllerBackedProtocol?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo? ) diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListViewFactory.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListViewFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewFactory.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListViewLayout.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewLayout.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListViewLayout.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewLayout.swift diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift new file mode 100644 index 0000000000..a20dad8b58 --- /dev/null +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift @@ -0,0 +1,192 @@ +import Foundation +import UIKit +import SoraFoundation + +final class CrowdloanListViewManager: NSObject { + let tableView: UITableView + let chainSelectionView: VoteChainViewProtocol + + var locale = Locale.current + + private weak var presenter: CrowdloanListPresenterProtocol? + private weak var parent: ControllerBackedProtocol? + + private var state: CrowdloanListState = .loading + + init(tableView: UITableView, chainSelectionView: VoteChainViewProtocol, parent: ControllerBackedProtocol) { + self.tableView = tableView + self.chainSelectionView = chainSelectionView + self.parent = parent + + super.init() + + tableView.delegate = self + tableView.dataSource = self + } +} + +extension CrowdloanListViewManager: UITableViewDataSource { + func numberOfSections(in _: UITableView) -> Int { + switch state { + case let .loaded(viewModel): + return viewModel.sections.count + case .loading: + return 0 + } + } + + func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { + switch state { + case let .loaded(viewModel): + let sectionModel = viewModel.sections[section] + switch sectionModel { + case let .active(_, cellViewModels): + return cellViewModels.count + case let .completed(_, cellViewModels): + return cellViewModels.count + case .yourContributions, .about, .error, .empty: + return 1 + } + case .loading: + return 0 + } + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + switch state { + case let .loaded(viewModel): + let sectionModel = viewModel.sections[indexPath.section] + switch sectionModel { + case let .active(_, cellViewModels), let .completed(_, cellViewModels): + let cell = tableView.dequeueReusableCellWithType(CrowdloanTableViewCell.self)! + let cellViewModel = cellViewModels[indexPath.row] + cell.bind(viewModel: cellViewModel) + return cell + case let .yourContributions(model): + let cell = tableView.dequeueReusableCellWithType(YourContributionsTableViewCell.self)! + cell.view.bind(model: model) + return cell + case let .about(model): + let cell = tableView.dequeueReusableCellWithType(AboutCrowdloansTableViewCell.self)! + cell.view.bind(model: model) + return cell + case let .error(message): + let cell: BlurredTableViewCell = tableView.dequeueReusableCell(for: indexPath) + cell.view.errorDescriptionLabel.text = message + cell.view.delegate = self + cell.view.locale = locale + cell.applyStyle() + return cell + case .empty: + let cell: BlurredTableViewCell = tableView.dequeueReusableCell(for: indexPath) + let text = R.string.localizable.crowdloanEmptyMessage_v3_9_1(preferredLanguages: locale.rLanguages) + cell.view.bind( + image: R.image.iconEmptyHistory(), + text: text + ) + cell.applyStyle() + return cell + } + case .loading: + return UITableViewCell() + } + } +} + +extension CrowdloanListViewManager: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + guard case let .loaded(viewModel) = state else { + return + } + + let sectionModel = viewModel.sections[indexPath.section] + switch sectionModel { + case let .active(_, cellViewModels): + let viewModel = cellViewModels[indexPath.row] + presenter?.selectCrowdloan(viewModel.paraId) + case .yourContributions: + presenter?.handleYourContributions() + default: + return + } + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + guard case let .loaded(viewModel) = state else { + return nil + } + + let sectionModel = viewModel.sections[section] + switch sectionModel { + case let .active(title, cells), let .completed(title, cells): + let headerView: CrowdloanStatusSectionView = tableView.dequeueReusableHeaderFooterView() + headerView.bind(title: title, count: cells.count) + return headerView + case let .empty(title): + let headerView: CrowdloanStatusSectionView = tableView.dequeueReusableHeaderFooterView() + headerView.bind(title: title, count: 0) + return headerView + default: + return nil + } + } + + func tableView(_: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + guard case let .loaded(viewModel) = state else { + return 0.0 + } + + let sectionModel = viewModel.sections[section] + switch sectionModel { + case .active, .completed, .empty: + return UITableView.automaticDimension + default: + return 0.0 + } + } +} + +extension CrowdloanListViewManager: ErrorStateViewDelegate { + func didRetry(errorView _: ErrorStateView) { + presenter?.refresh(shouldReset: true) + } +} + +extension CrowdloanListViewManager: CrowdloansViewProtocol { + func didReceive(chainInfo: CrowdloansChainViewModel) { + chainSelectionView.bind(viewModel: chainInfo) + } + + func didReceive(listState: CrowdloanListState) { + state = listState + + tableView.reloadData() + } +} + +// TODO: Implement for Moonbeam coordinator +extension CrowdloanListViewManager: LoadableViewProtocol { + var loadableContentView: UIView! { + UIView() + } + + var shouldDisableInteractionWhenLoading: Bool { + false + } + + func didStartLoading() {} + + func didStopLoading() {} +} + +extension CrowdloanListViewManager: VoteChildViewProtocol { + var isSetup: Bool { + parent?.isSetup ?? false + } + + var controller: UIViewController { + parent?.controller ?? UIViewController() + } +} diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift similarity index 96% rename from novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift index 1df247ba40..a08ee3f9e9 100644 --- a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift @@ -18,7 +18,7 @@ final class CrowdloanListWireframe: CrowdloanListWireframeProtocol { } func presentContributionSetup( - from view: CrowdloanListViewProtocol?, + from view: ControllerBackedProtocol?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo? ) { @@ -65,7 +65,7 @@ final class CrowdloanListWireframe: CrowdloanListWireframeProtocol { view?.controller.navigationController?.pushViewController(contributionsModule.controller, animated: true) } - private func showContributionSetup(from view: CrowdloanListViewProtocol?, paraId: ParaId) { + private func showContributionSetup(from view: ControllerBackedProtocol?, paraId: ParaId) { guard let setupView = CrowdloanContributionSetupViewFactory.createView( for: paraId, state: state diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloansCalculator.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansCalculator.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/CrowdloansCalculator.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansCalculator.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/View/AboutCrowdloansView.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/AboutCrowdloansView.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/View/AboutCrowdloansView.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/AboutCrowdloansView.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanEmptyView.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanEmptyView.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanEmptyView.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanEmptyView.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanStatusSectionView.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanStatusSectionView.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanStatusSectionView.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanStatusSectionView.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift similarity index 97% rename from novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift index 2e974e47e6..00f47c2610 100644 --- a/novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift @@ -39,23 +39,6 @@ final class CrowdloanTableHeaderView: UIView { fatalError("init(coder:) has not been implemented") } - func bind(viewModel: CrowdloansChainViewModel) { - self.viewModel?.imageViewModel?.cancel(on: chainSelectionView.iconView) - chainSelectionView.iconView.image = nil - - self.viewModel = viewModel - - chainSelectionView.title = viewModel.networkName - chainSelectionView.subtitle = viewModel.balance - - let iconSize = 2 * chainSelectionView.iconRadius - viewModel.imageViewModel?.loadImage( - on: chainSelectionView.iconView, - targetSize: CGSize(width: iconSize, height: iconSize), - animated: true - ) - } - private func setupLayout() { addSubview(walletSwitch) walletSwitch.snp.makeConstraints { make in @@ -93,3 +76,24 @@ final class CrowdloanTableHeaderView: UIView { } } } + +extension CrowdloanTableHeaderView: VoteChainViewProtocol { + func bind(viewModel: CrowdloansChainViewModel) { + self.viewModel?.imageViewModel?.cancel(on: chainSelectionView.iconView) + chainSelectionView.iconView.image = nil + + self.viewModel = viewModel + + chainSelectionView.title = viewModel.networkName + chainSelectionView.subtitle = viewModel.balance + + let iconSize = 2 * chainSelectionView.iconRadius + viewModel.imageViewModel?.loadImage( + on: chainSelectionView.iconView, + targetSize: CGSize(width: iconSize, height: iconSize), + animated: true + ) + + setNeedsLayout() + } +} diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanTableViewCell.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableViewCell.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/View/CrowdloanTableViewCell.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableViewCell.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/View/YourContributionsView.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/YourContributionsView.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/View/YourContributionsView.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/YourContributionsView.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/ViewModel/CrowdloansChainViewModel.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansChainViewModel.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/ViewModel/CrowdloansChainViewModel.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansChainViewModel.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewInfo.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewInfo.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewInfo.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewInfo.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModel.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModel.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModel.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModel.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModelFactory.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModelFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModelFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModelFactory.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsInteractor.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsInteractor.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsInteractor.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsInteractor.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsPresenter.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsPresenter.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsPresenter.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsPresenter.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsProtocols.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsProtocols.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsProtocols.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewController.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewController.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewController.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewController.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewFactory.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsViewFactory.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsWireframe.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsWireframe.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsWireframe.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsWireframe.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsCell.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsCell.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsCell.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsCell.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsTotalCell.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsTotalCell.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsTotalCell.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsTotalCell.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsViewLayout.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsViewLayout.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsViewLayout.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/View/CrowdloanYourContributionsViewLayout.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanContributionViewModel.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanContributionViewModel.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanContributionViewModel.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanContributionViewModel.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsVMFactory.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsVMFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsVMFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsVMFactory.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsViewModel.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsViewModel.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsViewModel.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/CrowdloanYourContributionsViewModel.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/FormattedReturnInIntervalsViewModel.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/FormattedReturnInIntervalsViewModel.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/FormattedReturnInIntervalsViewModel.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/FormattedReturnInIntervalsViewModel.swift diff --git a/novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/ReturnInIntervalsViewModel.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/ReturnInIntervalsViewModel.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CrowdloanYourContributions/ViewModel/ReturnInIntervalsViewModel.swift rename to novawallet/Modules/Vote/Crowdloan/CrowdloanYourContributions/ViewModel/ReturnInIntervalsViewModel.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/AcalaBonusService.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/AcalaBonusService.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/AcalaBonusService.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/AcalaBonusService.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/AcalaKeys.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/AcalaKeys.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/AcalaKeys.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/AcalaKeys.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/AcalaStatementData.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/AcalaStatementData.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/AcalaStatementData.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/AcalaStatementData.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/AcalaTransferRequest.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/AcalaTransferRequest.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/AcalaTransferRequest.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/AcalaTransferRequest.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmPresenter.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmPresenter.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmPresenter.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmPresenter.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmProtocols.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmProtocols.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmProtocols.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmVC.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmVC.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmVC.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmVC.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmViewFactory.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmViewFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmViewFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionConfirm/AcalaContributionConfirmViewFactory.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupPresenter.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupPresenter.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupPresenter.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupPresenter.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupProtocols.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupProtocols.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupProtocols.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewController.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewController.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewController.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewController.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewFactory.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewFactory.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewLayout.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewLayout.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewLayout.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupViewLayout.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupWireframe.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupWireframe.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupWireframe.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/AcalaContributionSetupWireframe.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/Model/AcalaContributionMethod.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/Model/AcalaContributionMethod.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/Model/AcalaContributionMethod.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Acala/ContributionSetup/Model/AcalaContributionMethod.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Astar/AstarBonusService.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Astar/AstarBonusService.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Astar/AstarBonusService.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Astar/AstarBonusService.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Astar/AstarBonusServiceError.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Astar/AstarBonusServiceError.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Astar/AstarBonusServiceError.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Astar/AstarBonusServiceError.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Bifrost/BifrostBonusService.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Bifrost/BifrostBonusService.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Bifrost/BifrostBonusService.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Bifrost/BifrostBonusService.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/CrowdloanBonusService.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/CrowdloanBonusService.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/CrowdloanBonusService.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/CrowdloanBonusService.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/CrowdloanBonusServiceError.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/CrowdloanBonusServiceError.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/CrowdloanBonusServiceError.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/CrowdloanBonusServiceError.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/CustomCrowdloanDelegate.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/CustomCrowdloanDelegate.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/CustomCrowdloanDelegate.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/CustomCrowdloanDelegate.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Karura/KaruraBonusService.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Karura/KaruraBonusService.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Karura/KaruraBonusService.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Karura/KaruraBonusService.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Karura/KaruraResultData.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Karura/KaruraResultData.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Karura/KaruraResultData.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Karura/KaruraResultData.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Karura/KaruraStatementData.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Karura/KaruraStatementData.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Karura/KaruraStatementData.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Karura/KaruraStatementData.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Karura/KaruraVerifyInfo.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Karura/KaruraVerifyInfo.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Karura/KaruraVerifyInfo.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Karura/KaruraVerifyInfo.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamCoordinator.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamCoordinator.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamCoordinator.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamCoordinator.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamFlowCoordinatorFactory.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamFlowCoordinatorFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamFlowCoordinatorFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Coordinator/MoonbeamFlowCoordinatorFactory.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamBonusService.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamBonusService.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamBonusService.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamBonusService.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamKeys.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamKeys.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamKeys.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamKeys.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsInteractor.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsInteractor.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsInteractor.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsInteractor.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsPresenter.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsPresenter.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsPresenter.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsPresenter.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsProtocols.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsProtocols.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsProtocols.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewController.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewController.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewController.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewController.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewFactory.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewFactory.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewFactory.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewLayout.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewLayout.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewLayout.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsViewLayout.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsWireframe.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsWireframe.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsWireframe.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/MoonbeamTerms/MoonbeamTermsWireframe.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkRequest.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkRequest.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkRequest.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkRequest.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkResponse.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkResponse.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkResponse.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamAgreeRemarkResponse.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureRequest.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureRequest.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureRequest.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureRequest.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureResponse.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureResponse.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureResponse.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamMakeSignatureResponse.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifiedResponse.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifiedResponse.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifiedResponse.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifiedResponse.swift diff --git a/novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifyRemarkRequest.swift b/novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifyRemarkRequest.swift similarity index 100% rename from novawallet/Modules/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifyRemarkRequest.swift rename to novawallet/Modules/Vote/Crowdloan/CustomCrowdloan/Moonbeam/Network/MoonbeamVerifyRemarkRequest.swift diff --git a/novawallet/Modules/Crowdloan/Model/Crowdloan.swift b/novawallet/Modules/Vote/Crowdloan/Model/Crowdloan.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Model/Crowdloan.swift rename to novawallet/Modules/Vote/Crowdloan/Model/Crowdloan.swift diff --git a/novawallet/Modules/Crowdloan/Model/CrowdloanContributionDict.swift b/novawallet/Modules/Vote/Crowdloan/Model/CrowdloanContributionDict.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Model/CrowdloanContributionDict.swift rename to novawallet/Modules/Vote/Crowdloan/Model/CrowdloanContributionDict.swift diff --git a/novawallet/Modules/Crowdloan/Model/CrowdloanDisplayInfo.swift b/novawallet/Modules/Vote/Crowdloan/Model/CrowdloanDisplayInfo.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Model/CrowdloanDisplayInfo.swift rename to novawallet/Modules/Vote/Crowdloan/Model/CrowdloanDisplayInfo.swift diff --git a/novawallet/Modules/Crowdloan/Model/CrowdloanFlow.swift b/novawallet/Modules/Vote/Crowdloan/Model/CrowdloanFlow.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Model/CrowdloanFlow.swift rename to novawallet/Modules/Vote/Crowdloan/Model/CrowdloanFlow.swift diff --git a/novawallet/Modules/Crowdloan/Model/CrowdloanMetadata.swift b/novawallet/Modules/Vote/Crowdloan/Model/CrowdloanMetadata.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Model/CrowdloanMetadata.swift rename to novawallet/Modules/Vote/Crowdloan/Model/CrowdloanMetadata.swift diff --git a/novawallet/Modules/Crowdloan/Model/CrowdloanSharedState.swift b/novawallet/Modules/Vote/Crowdloan/Model/CrowdloanSharedState.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Model/CrowdloanSharedState.swift rename to novawallet/Modules/Vote/Crowdloan/Model/CrowdloanSharedState.swift diff --git a/novawallet/Modules/Crowdloan/Model/CrowdloanStatus.swift b/novawallet/Modules/Vote/Crowdloan/Model/CrowdloanStatus.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Model/CrowdloanStatus.swift rename to novawallet/Modules/Vote/Crowdloan/Model/CrowdloanStatus.swift diff --git a/novawallet/Modules/Crowdloan/Model/ParachainLeaseInfo.swift b/novawallet/Modules/Vote/Crowdloan/Model/ParachainLeaseInfo.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Model/ParachainLeaseInfo.swift rename to novawallet/Modules/Vote/Crowdloan/Model/ParachainLeaseInfo.swift diff --git a/novawallet/Modules/Crowdloan/Operation/CrowdloanContributionResponse.swift b/novawallet/Modules/Vote/Crowdloan/Operation/CrowdloanContributionResponse.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/CrowdloanContributionResponse.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/CrowdloanContributionResponse.swift diff --git a/novawallet/Modules/Crowdloan/Operation/CrowdloanOperationFactory.swift b/novawallet/Modules/Vote/Crowdloan/Operation/CrowdloanOperationFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/CrowdloanOperationFactory.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/CrowdloanOperationFactory.swift diff --git a/novawallet/Modules/Crowdloan/Operation/ExternalContibution/AcalaContributionSource.swift b/novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/AcalaContributionSource.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/ExternalContibution/AcalaContributionSource.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/AcalaContributionSource.swift diff --git a/novawallet/Modules/Crowdloan/Operation/ExternalContibution/AcalaLiquidContributionResponse.swift b/novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/AcalaLiquidContributionResponse.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/ExternalContibution/AcalaLiquidContributionResponse.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/AcalaLiquidContributionResponse.swift diff --git a/novawallet/Modules/Crowdloan/Operation/ExternalContibution/ExternalContribution.swift b/novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/ExternalContribution.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/ExternalContibution/ExternalContribution.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/ExternalContribution.swift diff --git a/novawallet/Modules/Crowdloan/Operation/ExternalContibution/ExternalContributionSource.swift b/novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/ExternalContributionSource.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/ExternalContibution/ExternalContributionSource.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/ExternalContributionSource.swift diff --git a/novawallet/Modules/Crowdloan/Operation/ExternalContibution/ParallelContributionResponse.swift b/novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/ParallelContributionResponse.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/ExternalContibution/ParallelContributionResponse.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/ParallelContributionResponse.swift diff --git a/novawallet/Modules/Crowdloan/Operation/ExternalContibution/ParallelContributionSource.swift b/novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/ParallelContributionSource.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/ExternalContibution/ParallelContributionSource.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/ExternalContibution/ParallelContributionSource.swift diff --git a/novawallet/Modules/Crowdloan/Operation/LeaseParam.swift b/novawallet/Modules/Vote/Crowdloan/Operation/LeaseParam.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/LeaseParam.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/LeaseParam.swift diff --git a/novawallet/Modules/Crowdloan/Operation/UInt32+CrowdloanAccountId.swift b/novawallet/Modules/Vote/Crowdloan/Operation/UInt32+CrowdloanAccountId.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Operation/UInt32+CrowdloanAccountId.swift rename to novawallet/Modules/Vote/Crowdloan/Operation/UInt32+CrowdloanAccountId.swift diff --git a/novawallet/Modules/Crowdloan/Protocols/CrowdloanErrorPresentable.swift b/novawallet/Modules/Vote/Crowdloan/Protocols/CrowdloanErrorPresentable.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Protocols/CrowdloanErrorPresentable.swift rename to novawallet/Modules/Vote/Crowdloan/Protocols/CrowdloanErrorPresentable.swift diff --git a/novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanPresenter.swift b/novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanPresenter.swift similarity index 100% rename from novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanPresenter.swift rename to novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanPresenter.swift diff --git a/novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanProtocols.swift b/novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanProtocols.swift similarity index 100% rename from novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanProtocols.swift rename to novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanProtocols.swift diff --git a/novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewController.swift b/novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewController.swift similarity index 100% rename from novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewController.swift rename to novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewController.swift diff --git a/novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewFactory.swift b/novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewFactory.swift rename to novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewFactory.swift diff --git a/novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewLayout.swift b/novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewLayout.swift similarity index 100% rename from novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewLayout.swift rename to novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanViewLayout.swift diff --git a/novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanWireframe.swift b/novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanWireframe.swift similarity index 100% rename from novawallet/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanWireframe.swift rename to novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanWireframe.swift diff --git a/novawallet/Modules/Crowdloan/ReferralCrowdloan/ViewModel/AttributedString+Crowdloan.swift b/novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ViewModel/AttributedString+Crowdloan.swift similarity index 100% rename from novawallet/Modules/Crowdloan/ReferralCrowdloan/ViewModel/AttributedString+Crowdloan.swift rename to novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ViewModel/AttributedString+Crowdloan.swift diff --git a/novawallet/Modules/Crowdloan/ReferralCrowdloan/ViewModel/ReferralCrowdloanViewModel.swift b/novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ViewModel/ReferralCrowdloanViewModel.swift similarity index 100% rename from novawallet/Modules/Crowdloan/ReferralCrowdloan/ViewModel/ReferralCrowdloanViewModel.swift rename to novawallet/Modules/Vote/Crowdloan/ReferralCrowdloan/ViewModel/ReferralCrowdloanViewModel.swift diff --git a/novawallet/Modules/Crowdloan/Validation/CrowdloanDataValidatorFactory.swift b/novawallet/Modules/Vote/Crowdloan/Validation/CrowdloanDataValidatorFactory.swift similarity index 100% rename from novawallet/Modules/Crowdloan/Validation/CrowdloanDataValidatorFactory.swift rename to novawallet/Modules/Vote/Crowdloan/Validation/CrowdloanDataValidatorFactory.swift diff --git a/novawallet/Modules/Crowdloan/View/BlurredTableViewCell.swift b/novawallet/Modules/Vote/Crowdloan/View/BlurredTableViewCell.swift similarity index 100% rename from novawallet/Modules/Crowdloan/View/BlurredTableViewCell.swift rename to novawallet/Modules/Vote/Crowdloan/View/BlurredTableViewCell.swift diff --git a/novawallet/Modules/Crowdloan/View/CrowdloanRewardDestinationView.swift b/novawallet/Modules/Vote/Crowdloan/View/CrowdloanRewardDestinationView.swift similarity index 100% rename from novawallet/Modules/Crowdloan/View/CrowdloanRewardDestinationView.swift rename to novawallet/Modules/Vote/Crowdloan/View/CrowdloanRewardDestinationView.swift diff --git a/novawallet/Modules/Crowdloan/ViewModel/CrowdloanRewardDestinationVM.swift b/novawallet/Modules/Vote/Crowdloan/ViewModel/CrowdloanRewardDestinationVM.swift similarity index 100% rename from novawallet/Modules/Crowdloan/ViewModel/CrowdloanRewardDestinationVM.swift rename to novawallet/Modules/Vote/Crowdloan/ViewModel/CrowdloanRewardDestinationVM.swift diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift new file mode 100644 index 0000000000..66c5c8ab86 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -0,0 +1,3 @@ +import Foundation + +protocol ReferendumsViewProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift new file mode 100644 index 0000000000..2b85055e1e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -0,0 +1,27 @@ +import Foundation +import UIKit + +final class ReferendumsViewManager { + let tableView: UITableView + + var locale = Locale.current + + private weak var parent: ControllerBackedProtocol? + + init(tableView: UITableView, parent: ControllerBackedProtocol) { + self.tableView = tableView + self.parent = parent + } +} + +extension ReferendumsViewManager: ReferendumsViewProtocol {} + +extension ReferendumsViewManager: VoteChildViewProtocol { + var isSetup: Bool { + parent?.isSetup ?? false + } + + var controller: UIViewController { + parent?.controller ?? UIViewController() + } +} diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift new file mode 100644 index 0000000000..49d3f97697 --- /dev/null +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -0,0 +1,131 @@ +import Foundation +import SoraFoundation +import RobinHood +import SubstrateSdk + +protocol VoteChildPresenterFactoryProtocol { + func createCrowdloanPresenter( + from view: CrowdloansViewProtocol, + wallet: MetaAccountModel + ) -> VoteChildPresenterProtocol? + + func createGovernancePresenter( + from view: ReferendumsViewProtocol, + wallet: MetaAccountModel + ) -> VoteChildPresenterProtocol? +} + +final class VoteChildPresenterFactory { + let currencyManager: CurrencyManagerProtocol + let localizationManager: LocalizationManagerProtocol + let repositoryFactory: SubstrateRepositoryFactoryProtocol + let chainRegistry: ChainRegistryProtocol + let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol + let jsonDataProviderFactory: JsonDataProviderFactoryProtocol + let priceProviderFactory: PriceProviderFactoryProtocol + let applicationHandler: ApplicationHandlerProtocol + let operationQueue: OperationQueue + let logger: LoggerProtocol + + init( + currencyManager: CurrencyManagerProtocol, + chainRegistry: ChainRegistryProtocol = ChainRegistryFacade.sharedRegistry, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol = WalletLocalSubscriptionFactory.shared, + jsonDataProviderFactory: JsonDataProviderFactoryProtocol = JsonDataProviderFactory.shared, + priceProviderFactory: PriceProviderFactoryProtocol = PriceProviderFactory.shared, + repositoryFactory: SubstrateRepositoryFactoryProtocol = SubstrateRepositoryFactory(), + applicationHandler: ApplicationHandlerProtocol = ApplicationHandler(), + operationQueue: OperationQueue = OperationManagerFacade.sharedDefaultQueue, + localizationManager: LocalizationManagerProtocol = LocalizationManager.shared, + logger: LoggerProtocol = Logger.shared + ) { + self.currencyManager = currencyManager + self.chainRegistry = chainRegistry + self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory + self.jsonDataProviderFactory = jsonDataProviderFactory + self.priceProviderFactory = priceProviderFactory + self.repositoryFactory = repositoryFactory + self.applicationHandler = applicationHandler + self.operationQueue = operationQueue + self.localizationManager = localizationManager + self.logger = logger + } + + private func createCrowdloanInteractor( + from state: CrowdloanSharedState, + wallet: MetaAccountModel + ) -> CrowdloanListInteractor { + let repository = repositoryFactory.createChainStorageItemRepository() + + let operationManager = OperationManager(operationQueue: operationQueue) + + let crowdloanRemoteSubscriptionService = CrowdloanRemoteSubscriptionService( + chainRegistry: chainRegistry, + repository: AnyDataProviderRepository(repository), + operationManager: operationManager, + logger: logger + ) + + let storageRequestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: operationManager + ) + + let crowdloanOperationFactory = CrowdloanOperationFactory( + requestOperationFactory: storageRequestFactory, + operationManager: operationManager + ) + + return CrowdloanListInteractor( + selectedMetaAccount: wallet, + crowdloanState: state, + chainRegistry: chainRegistry, + crowdloanOperationFactory: crowdloanOperationFactory, + crowdloanRemoteSubscriptionService: crowdloanRemoteSubscriptionService, + walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, + jsonDataProviderFactory: jsonDataProviderFactory, + operationManager: operationManager, + applicationHandler: applicationHandler, + currencyManager: currencyManager, + priceLocalSubscriptionFactory: priceProviderFactory, + logger: logger + ) + } +} + +extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { + func createCrowdloanPresenter( + from _: CrowdloansViewProtocol, + wallet: MetaAccountModel + ) -> VoteChildPresenterProtocol? { + let state = CrowdloanSharedState() + + let interactor = createCrowdloanInteractor(from: state, wallet: wallet) + let wireframe = CrowdloanListWireframe(state: state) + + let viewModelFactory = CrowdloansViewModelFactory( + amountFormatterFactory: AssetBalanceFormatterFactory(), + balanceViewModelFactoryFacade: BalanceViewModelFactoryFacade( + priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) + ) + ) + + let presenter = CrowdloanListPresenter( + interactor: interactor, + wireframe: wireframe, + wallet: wallet, + viewModelFactory: viewModelFactory, + localizationManager: localizationManager, + crowdloansCalculator: CrowdloansCalculator(), + accountManagementFilter: AccountManagementFilter(), + logger: Logger.shared + ) + + return presenter + } + + func createGovernancePresenter( + from _: ReferendumsViewProtocol, + wallet _: MetaAccountModel + ) -> VoteChildPresenterProtocol? {} +} diff --git a/novawallet/Modules/Vote/Parent/VoteInteractor.swift b/novawallet/Modules/Vote/Parent/VoteInteractor.swift new file mode 100644 index 0000000000..50d9784303 --- /dev/null +++ b/novawallet/Modules/Vote/Parent/VoteInteractor.swift @@ -0,0 +1,42 @@ +import Foundation + +final class VoteInteractor { + weak var presenter: VoteInteractorOutputProtocol? + + let walletSettings: SelectedWalletSettings + let eventCenter: EventCenterProtocol + + init( + walletSettings: SelectedWalletSettings, + eventCenter: EventCenterProtocol + ) { + self.walletSettings = walletSettings + self.eventCenter = eventCenter + } + + private func provideSelectedWallet() { + guard let selectedWallet = walletSettings.value else { + return + } + + presenter?.didReceiveWallet(selectedWallet) + } +} + +extension VoteInteractor: VoteInteractorInputProtocol { + func setup() { + provideSelectedWallet() + + eventCenter.add(observer: self) + } +} + +extension VoteInteractor: EventVisitorProtocol { + func processSelectedAccountChanged(event _: SelectedAccountChanged) { + provideSelectedWallet() + } + + func processChainAccountChanged(event _: ChainAccountChanged) { + provideSelectedWallet() + } +} diff --git a/novawallet/Modules/Vote/Parent/VotePresenter.swift b/novawallet/Modules/Vote/Parent/VotePresenter.swift new file mode 100644 index 0000000000..02beee21f0 --- /dev/null +++ b/novawallet/Modules/Vote/Parent/VotePresenter.swift @@ -0,0 +1,81 @@ +import Foundation + +final class VotePresenter { + weak var view: VoteViewProtocol? + + let interactor: VoteInteractorInputProtocol + let wireframe: VoteWireframeProtocol + let childPresenterFactory: VoteChildPresenterFactoryProtocol + + private var childPresenter: VoteChildPresenterProtocol? + private var wallet: MetaAccountModel? + + private lazy var walletSwitchViewModelFactory = WalletSwitchViewModelFactory() + + init( + interactor: VoteInteractorInputProtocol, + wireframe: VoteWireframeProtocol, + childPresenterFactory: VoteChildPresenterFactoryProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + self.childPresenterFactory = childPresenterFactory + } + + private func provideWalletViewModel() { + guard let wallet = wallet else { + return + } + + let viewModel = walletSwitchViewModelFactory.createViewModel(from: wallet.walletIdenticonData(), walletType: wallet.type) + view?.didSwitchWallet(with: viewModel) + } +} + +extension VotePresenter: VotePresenterProtocol { + func setup() { + interactor.setup() + } + + func becomeOnline() { + childPresenter?.becomeOnline() + } + + func putOffline() { + childPresenter?.putOffline() + } + + func selectChain() { + childPresenter?.selectChain() + } + + func selectWallet() { + wireframe.showWalletSwitch(from: view) + } + + func switchToGovernance(_ view: ReferendumsViewProtocol) { + guard let wallet = wallet else { + return + } + + childPresenter = childPresenterFactory.createGovernancePresenter(from: view, wallet: wallet) + childPresenter?.setup() + } + + func switchToCrowdloans(_ view: CrowdloansViewProtocol) { + guard let wallet = wallet else { + return + } + + childPresenter = childPresenterFactory.createCrowdloanPresenter(from: view, wallet: wallet) + childPresenter?.setup() + } +} + +extension VotePresenter: VoteInteractorOutputProtocol { + func didReceiveWallet(_ wallet: MetaAccountModel) { + self.wallet = wallet + + provideWalletViewModel() + } +} diff --git a/novawallet/Modules/Vote/Parent/VoteProtocols.swift b/novawallet/Modules/Vote/Parent/VoteProtocols.swift new file mode 100644 index 0000000000..0d6b4d1983 --- /dev/null +++ b/novawallet/Modules/Vote/Parent/VoteProtocols.swift @@ -0,0 +1,45 @@ +import Foundation + +enum VoteType: UInt8 { + case governance + case crowdloan +} + +protocol VoteViewProtocol: ControllerBackedProtocol { + func didSwitchWallet(with viewModel: WalletSwitchViewModel) +} + +protocol VoteChainViewProtocol { + func bind(viewModel: CrowdloansChainViewModel) +} + +protocol VotePresenterProtocol: AnyObject { + func setup() + func becomeOnline() + func putOffline() + func selectChain() + func selectWallet() + func switchToGovernance(_ view: ReferendumsViewProtocol) + func switchToCrowdloans(_ view: CrowdloansViewProtocol) +} + +protocol VoteInteractorInputProtocol: AnyObject { + func setup() +} + +protocol VoteInteractorOutputProtocol: AnyObject { + func didReceiveWallet(_ wallet: MetaAccountModel) +} + +protocol VoteWireframeProtocol: AlertPresentable, ErrorPresentable, WalletSwitchPresentable {} + +protocol VoteChildViewProtocol: ControllerBackedProtocol { + var locale: Locale { get set } +} + +protocol VoteChildPresenterProtocol: AnyObject { + func setup() + func becomeOnline() + func putOffline() + func selectChain() +} diff --git a/novawallet/Modules/Vote/Parent/VoteViewController.swift b/novawallet/Modules/Vote/Parent/VoteViewController.swift new file mode 100644 index 0000000000..5f7dd76c5c --- /dev/null +++ b/novawallet/Modules/Vote/Parent/VoteViewController.swift @@ -0,0 +1,136 @@ +import Foundation +import UIKit +import SoraFoundation + +final class VoteViewController: UIViewController, ViewHolder { + typealias RootViewType = VoteViewLayout + + let presenter: VotePresenterProtocol + + private(set) var childView: VoteChildViewProtocol? + + var selectedType: VoteType { + VoteType(rawValue: UInt8(rootView.headerView.votingTypeSwitch.selectedSegmentIndex)) ?? .governance + } + + init( + presenter: VotePresenterProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.presenter = presenter + + super.init(nibName: nil, bundle: nil) + + self.localizationManager = localizationManager + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = CrowdloanListViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + configure() + setupLocalization() + + presenter.setup() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + presenter.becomeOnline() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + presenter.putOffline() + } + + private func configure() { + rootView.headerView.chainSelectionView.addTarget( + self, + action: #selector(actionSelectChain), + for: .touchUpInside + ) + + rootView.headerView.walletSwitch.addTarget( + self, + action: #selector(actionWalletSwitch), + for: .touchUpInside + ) + + rootView.headerView.votingTypeSwitch.addTarget( + self, + action: #selector(actionVoteTypeChanged), + for: .valueChanged + ) + } + + private func setupLocalization() { + let languages = selectedLocale.rLanguages + rootView.headerView.titleLabel.text = R.string.localizable.tabbarVoteTitle(preferredLanguages: languages) + + childView?.locale = selectedLocale + } + + @objc func actionSelectChain() { + presenter.selectChain() + } + + @objc func actionWalletSwitch() { + presenter.selectWallet() + } + + @objc func actionVoteTypeChanged() { + setupChildView() + } + + private func setupChildView() { + switch selectedType { + case .governance: + let governanceChildView = ReferendumsViewManager( + tableView: rootView.tableView, + parent: self + ) + + childView = governanceChildView + + presenter.switchToGovernance(governanceChildView) + case .crowdloan: + let crowdloanChildView = CrowdloanListViewManager( + tableView: rootView.tableView, + chainSelectionView: rootView.headerView, + parent: self + ) + childView = crowdloanChildView + + presenter.switchToCrowdloans(crowdloanChildView) + } + + childView?.locale = selectedLocale + } +} + +extension VoteViewController: VoteViewProtocol { + func didSwitchWallet(with viewModel: WalletSwitchViewModel) { + rootView.headerView.walletSwitch.bind(viewModel: viewModel) + + setupChildView() + } +} + +extension VoteViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + setupLocalization() + } + } +} diff --git a/novawallet/Modules/Vote/Parent/VoteViewLayout.swift b/novawallet/Modules/Vote/Parent/VoteViewLayout.swift new file mode 100644 index 0000000000..36194f3483 --- /dev/null +++ b/novawallet/Modules/Vote/Parent/VoteViewLayout.swift @@ -0,0 +1,48 @@ +import Foundation +import UIKit + +final class VoteViewLayout: UIView, TableHeaderLayoutUpdatable { + private let backgroundView = MultigradientView.background + + let headerView = CrowdloanTableHeaderView() + + let tableView: UITableView = { + let view = UITableView() + view.backgroundColor = .clear + view.separatorColor = R.color.colorDarkGray() + view.refreshControl = UIRefreshControl() + view.tableFooterView = UIView() + view.separatorStyle = .none + view.contentInset = .init(top: 0, left: 0, bottom: 16, right: 0) + return view + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + setup() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + updateTableHeaderLayout(headerView) + } + + private func setup() { + addSubview(backgroundView) + backgroundView.snp.makeConstraints { $0.edges.equalToSuperview() } + + addSubview(tableView) + tableView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.leading.bottom.trailing.equalToSuperview() + } + tableView.tableHeaderView = headerView + } +} diff --git a/novawallet/Modules/Vote/Parent/VoteWireframe.swift b/novawallet/Modules/Vote/Parent/VoteWireframe.swift new file mode 100644 index 0000000000..f89d3cd5d3 --- /dev/null +++ b/novawallet/Modules/Vote/Parent/VoteWireframe.swift @@ -0,0 +1,5 @@ +import Foundation + +final class VoteWireframe {} + +extension VoteWireframe: VoteWireframeProtocol {} diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 2c9a8a70cc..625bfb7900 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -977,3 +977,5 @@ "yield.boost.task.not.found.message" = "Yield boost already disabled for the selected collator"; "common.not.available" = "N/A"; "wallet.account.locks.crowdloans" = "Crowdloans"; +"tabbar.vote.title" = "Vote"; +"tabbar.governance.title" = "Governance"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 62af0c73c2..9295d1004f 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -977,3 +977,5 @@ "yield.boost.task.not.found.message" = "Yield boost уже отключен для выбранного коллатора"; "common.not.available" = "N/A"; "wallet.account.locks.crowdloans" = "Краудлоуны"; +"tabbar.vote.title" = "Голосование"; +"tabbar.governance.title" = "Референдумы"; From ea5f0a7b27bdbc5133e5ab6f771f78555752bd29 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 3 Oct 2022 17:05:51 +0500 Subject: [PATCH 008/229] fix crowdloans --- novawallet.xcodeproj/project.pbxproj | 24 +++-- .../Extension/UIKit/UITableView+Reuse.swift | 10 ++ .../MainTabBar/MainTabBarInteractor.swift | 1 - .../MainTabBar/MainTabBarPresenter.swift | 4 - .../MainTabBar/MainTabBarProtocol.swift | 4 - .../MainTabBar/MainTabBarViewFactory.swift | 29 +----- .../MainTabBar/MainTabBarWireframe.swift | 6 -- .../CrowdloanListProtocols.swift | 4 +- .../CrowdloanListViewFactory.swift | 94 ------------------- .../CrowdloanListViewLayout.swift | 59 ------------ .../CrowdloanListViewManager.swift | 33 ++++++- .../CrowdloanListWireframe.swift | 2 +- .../CrowdloansListInteractor+Protocols.swift | 1 + .../Referendums/ReferendumsInteractor.swift | 7 ++ .../Referendums/ReferendumsPresenter.swift | 30 ++++++ .../Referendums/ReferendumsProtocols.swift | 12 ++- .../Referendums/ReferendumsViewManager.swift | 48 +++++++++- .../Referendums/ReferendumsWireframe.swift | 3 + .../Parent/VoteChildPresenterFactory.swift | 21 ++++- .../Modules/Vote/Parent/VoteInteractor.swift | 2 +- .../Modules/Vote/Parent/VotePresenter.swift | 2 + .../Modules/Vote/Parent/VoteProtocols.swift | 3 + .../Vote/Parent/VoteViewController.swift | 14 ++- .../Modules/Vote/Parent/VoteViewFactory.swift | 32 +++++++ .../Modules/Vote/Parent/VoteViewLayout.swift | 2 +- 25 files changed, 231 insertions(+), 216 deletions(-) delete mode 100644 novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewFactory.swift delete mode 100644 novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewLayout.swift create mode 100644 novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift create mode 100644 novawallet/Modules/Vote/Parent/VoteViewFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index fcdcfcb059..b08331f87c 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -76,7 +76,6 @@ 25993E2E536DE682E1DFC9AD /* ParaStkCollatorsSearchInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841C1EE99F5EA1713BA3F313 /* ParaStkCollatorsSearchInteractor.swift */; }; 270C21973CB61F0BF3D2D1E3 /* CrowdloanListProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02ACCC85B2CCF3D9392CA9B4 /* CrowdloanListProtocols.swift */; }; 2736BAABAE1389260A0B28D6 /* AssetListViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B754B68D6F1D1ED5C8577A5 /* AssetListViewFactory.swift */; }; - 278F5341DC043EBED7C0733D /* CrowdloanListViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E70C8A9C6BF8AE46CAE1CB61 /* CrowdloanListViewFactory.swift */; }; 2793D406FD618A892D54EA84 /* CrowdloanContributionConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C92E3ED704CB0BBAB3A669F /* CrowdloanContributionConfirmViewLayout.swift */; }; 27FA1D57A06AA3A030D226B6 /* StakingUnbondConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84638893DC99974E098719E /* StakingUnbondConfirmWireframe.swift */; }; 286577D8FE44D1F9E7BBDCA9 /* DAppSearchViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE0F7D4389B932A1F2E17361 /* DAppSearchViewLayout.swift */; }; @@ -212,7 +211,6 @@ 577918C3D4AA22D887F605B5 /* ParaStkStakeSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1AC788C6E0A621B6D88D1BC /* ParaStkStakeSetupPresenter.swift */; }; 57E20F0723C4748D576C4882 /* StakingUnbondSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82E373FFFBF708D7CF0973E /* StakingUnbondSetupViewFactory.swift */; }; 5869563D0EA593FBD02C169C /* StakingPayoutConfirmationProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F8D055D0481469073AA859 /* StakingPayoutConfirmationProtocols.swift */; }; - 5888936B3D13D92F1534E08B /* CrowdloanListViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63F4BE52D0625CD8C21D2460 /* CrowdloanListViewLayout.swift */; }; 58D5B4F17DA37C241FF96A5F /* ParaStkRebondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FDF5963FA924F8C815F3BCF /* ParaStkRebondViewController.swift */; }; 58F693958EF69F59D7C9760E /* StakingRewardPayoutsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4191E0055768541F6A3D8A61 /* StakingRewardPayoutsInteractor.swift */; }; 59745D3C9602745E1417D2F6 /* AssetSelectionInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83AB0AD3A7CECD061611F60C /* AssetSelectionInteractor.swift */; }; @@ -747,6 +745,10 @@ 8442002D28E9ADB500C49C4A /* VoteInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442002C28E9ADB500C49C4A /* VoteInteractor.swift */; }; 8442002F28E9AEFB00C49C4A /* VoteWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442002E28E9AEFB00C49C4A /* VoteWireframe.swift */; }; 8442003428E9BD3200C49C4A /* VoteChildPresenterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442003328E9BD3200C49C4A /* VoteChildPresenterFactory.swift */; }; + 8442003628EA9DF100C49C4A /* VoteViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442003528EA9DF100C49C4A /* VoteViewFactory.swift */; }; + 8442003828EAA16600C49C4A /* ReferendumsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442003728EAA16600C49C4A /* ReferendumsPresenter.swift */; }; + 8442003A28EAA2D400C49C4A /* ReferendumsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442003928EAA2D300C49C4A /* ReferendumsInteractor.swift */; }; + 8442003C28EAA2E400C49C4A /* ReferendumsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442003B28EAA2E400C49C4A /* ReferendumsWireframe.swift */; }; 844384AC28538D3000611CE2 /* RewardCalculatorEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844384AB28538D3000611CE2 /* RewardCalculatorEngine.swift */; }; 844384AE28538F4700611CE2 /* UniformCurveRewardEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844384AD28538F4700611CE2 /* UniformCurveRewardEngine.swift */; }; 844384B0285391D800611CE2 /* RewardCalculatorEngineFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844384AF285391D800611CE2 /* RewardCalculatorEngineFactory.swift */; }; @@ -3005,7 +3007,6 @@ 62C5AF7E89A8C6CFF5AE03B1 /* YourWalletsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourWalletsProtocols.swift; sourceTree = ""; }; 62FA66143B25AA70B02CE461 /* ExportSeedViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ExportSeedViewFactory.swift; sourceTree = ""; }; 638A65DAC86BAF9EB4D2F2F8 /* StakingRewardDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardDetailsWireframe.swift; sourceTree = ""; }; - 63F4BE52D0625CD8C21D2460 /* CrowdloanListViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanListViewLayout.swift; sourceTree = ""; }; 6475F9C6C6B095B9C5026CE9 /* ParaStkYieldBoostStartViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStartViewController.swift; sourceTree = ""; }; 65AD15693E21C869DE1FDD17 /* UsernameSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UsernameSetupWireframe.swift; sourceTree = ""; }; 661356CFE77B978610397907 /* OperationDetailsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OperationDetailsInteractor.swift; sourceTree = ""; }; @@ -3517,6 +3518,10 @@ 8442002C28E9ADB500C49C4A /* VoteInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteInteractor.swift; sourceTree = ""; }; 8442002E28E9AEFB00C49C4A /* VoteWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteWireframe.swift; sourceTree = ""; }; 8442003328E9BD3200C49C4A /* VoteChildPresenterFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteChildPresenterFactory.swift; sourceTree = ""; }; + 8442003528EA9DF100C49C4A /* VoteViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteViewFactory.swift; sourceTree = ""; }; + 8442003728EAA16600C49C4A /* ReferendumsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsPresenter.swift; sourceTree = ""; }; + 8442003928EAA2D300C49C4A /* ReferendumsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsInteractor.swift; sourceTree = ""; }; + 8442003B28EAA2E400C49C4A /* ReferendumsWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsWireframe.swift; sourceTree = ""; }; 844384AB28538D3000611CE2 /* RewardCalculatorEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardCalculatorEngine.swift; sourceTree = ""; }; 844384AD28538F4700611CE2 /* UniformCurveRewardEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniformCurveRewardEngine.swift; sourceTree = ""; }; 844384AF285391D800611CE2 /* RewardCalculatorEngineFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardCalculatorEngineFactory.swift; sourceTree = ""; }; @@ -5302,7 +5307,6 @@ E5CC1FB277A878E9C9B7EAEB /* AccountImportInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountImportInteractor.swift; sourceTree = ""; }; E63ECD1205B2CCCDA2E66A1E /* ParaStkYieldBoostSetupViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostSetupViewLayout.swift; sourceTree = ""; }; E675B4C5BE36C0004564105B /* DAppOperationConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmProtocols.swift; sourceTree = ""; }; - E70C8A9C6BF8AE46CAE1CB61 /* CrowdloanListViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanListViewFactory.swift; sourceTree = ""; }; E8B10C37813EFE7D7663605E /* ParitySignerAddressesWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddressesWireframe.swift; sourceTree = ""; }; E8C13B77688FFF0FFBBB6612 /* ParaStkYourCollatorsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYourCollatorsWireframe.swift; sourceTree = ""; }; E9636093217ABE05A7FAC9B9 /* AccountCreateViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountCreateViewFactory.swift; sourceTree = ""; }; @@ -7348,6 +7352,9 @@ children = ( 8442002228E6FE1E00C49C4A /* ReferendumsViewManager.swift */, 8442002428E6FEEE00C49C4A /* ReferendumsProtocols.swift */, + 8442003728EAA16600C49C4A /* ReferendumsPresenter.swift */, + 8442003928EAA2D300C49C4A /* ReferendumsInteractor.swift */, + 8442003B28EAA2E400C49C4A /* ReferendumsWireframe.swift */, ); path = Referendums; sourceTree = ""; @@ -7896,6 +7903,7 @@ 8442002C28E9ADB500C49C4A /* VoteInteractor.swift */, 8442002E28E9AEFB00C49C4A /* VoteWireframe.swift */, 8442003328E9BD3200C49C4A /* VoteChildPresenterFactory.swift */, + 8442003528EA9DF100C49C4A /* VoteViewFactory.swift */, ); path = Parent; sourceTree = ""; @@ -11699,8 +11707,6 @@ C191A3875F3255B72E01FA92 /* CrowdloanListWireframe.swift */, 86F7A369E31DCB9ABD556EE9 /* CrowdloanListPresenter.swift */, E4E78D69E8EBC3EB4D01F8EF /* CrowdloanListInteractor.swift */, - 63F4BE52D0625CD8C21D2460 /* CrowdloanListViewLayout.swift */, - E70C8A9C6BF8AE46CAE1CB61 /* CrowdloanListViewFactory.swift */, 84B66A0A26FDB70F0038B963 /* CrowdloansListInteractor+Protocols.swift */, 8828F4F228AD2734009E0B7C /* CrowdloansCalculator.swift */, 8828F4F428AD2763009E0B7C /* BalanceViewModelFactoryFacade.swift */, @@ -13903,6 +13909,7 @@ 84452F9325D5EE7300F47EC5 /* DataOperationFactory.swift in Sources */, 841E5538282CF3F400C8438F /* StakingMainViewModelFactory.swift in Sources */, F43A597026D535E2005E973D /* AnalyticsPresenterBaseProtocols.swift in Sources */, + 8442003C28EAA2E400C49C4A /* ReferendumsWireframe.swift in Sources */, 844DBC6F274E702C009F8351 /* AccountImportBaseView.swift in Sources */, 8466781A27ECA021007935D3 /* PersistentExtrinsicService.swift in Sources */, 8490151824AB8C6D008F705E /* WalletCommonStyleConfigurator.swift in Sources */, @@ -14770,6 +14777,7 @@ 8407715C28CBE25B007DBD24 /* ParaStkYieldBoostSetupPresenter+Schedule.swift in Sources */, 848CCB482832EF4400A1FD00 /* GeneralLocalStorageHandler.swift in Sources */, 849013D024A9267F008F705E /* R.generated.swift in Sources */, + 8442003828EAA16600C49C4A /* ReferendumsPresenter.swift in Sources */, 84FB9E22285C5D6200B42FC0 /* XcmNetworkId.swift in Sources */, 84DC3CE52796768A0038E2ED /* SubqueryHistoryContext.swift in Sources */, 848077D22837CAE5003B7C79 /* ParachainStakingErrorPresentable.swift in Sources */, @@ -14996,6 +15004,7 @@ AE6DE7322627EA930018D5B5 /* PayoutCall.swift in Sources */, 84DD5F26263D72C400425ACF /* ExtrinsicFeeProxy.swift in Sources */, F4433D7526C16BFB0002A91E /* AnalyticsValidatorItemViewModel.swift in Sources */, + 8442003628EA9DF100C49C4A /* VoteViewFactory.swift in Sources */, 84BC7041289DBF62008A9758 /* QRDisplayView.swift in Sources */, 2AC7BC7E2731604C001D99B0 /* ChainAccountChanged.swift in Sources */, 847C96492553614F002D288F /* ExportRestoreJsonPresenter.swift in Sources */, @@ -15616,11 +15625,9 @@ 846CA7802709A41E0011124C /* StakingAnalyticsLocalSubscriptionHandler.swift in Sources */, 849DF02D26C40B7900B702F4 /* RuntimeFilesOperationFactory.swift in Sources */, 0B2B9C6E2BA2E924D6A54F4B /* CrowdloanListInteractor.swift in Sources */, - 5888936B3D13D92F1534E08B /* CrowdloanListViewLayout.swift in Sources */, 849C066F2765140B00394C82 /* AnyCancellableCleaning.swift in Sources */, 8489A6D627FDA50D0040C066 /* AccountLocalStorageSubscriber.swift in Sources */, 846F758727B5550700536547 /* EthereumRpcRequest.swift in Sources */, - 278F5341DC043EBED7C0733D /* CrowdloanListViewFactory.swift in Sources */, 8490895028D4A2DC00C3CCE9 /* WeightCompatabilityNode.swift in Sources */, 7CBE9FFAF8394786CA131D4D /* CustomValidatorListProtocols.swift in Sources */, 84D9C8EF28AD97E7007FB23B /* SupportedLedgerApps.swift in Sources */, @@ -15732,6 +15739,7 @@ 84117074285B0E92006F4DFB /* XcmChain.swift in Sources */, 844D2A42281B24510049CF5E /* StackUrlCell.swift in Sources */, 98DADEB52480817D191188C1 /* AssetListInteractor.swift in Sources */, + 8442003A28EAA2D400C49C4A /* ReferendumsInteractor.swift in Sources */, 8448D5B6277D717400FAEEBC /* DAppListDecorationView.swift in Sources */, 84CC986B287D7BAA0085431C /* RMRKV2Collection.swift in Sources */, 844384B0285391D800611CE2 /* RewardCalculatorEngineFactory.swift in Sources */, diff --git a/novawallet/Common/Extension/UIKit/UITableView+Reuse.swift b/novawallet/Common/Extension/UIKit/UITableView+Reuse.swift index 3081cbd546..21eb7f65af 100644 --- a/novawallet/Common/Extension/UIKit/UITableView+Reuse.swift +++ b/novawallet/Common/Extension/UIKit/UITableView+Reuse.swift @@ -5,6 +5,11 @@ extension UITableView { register(cellClass, forCellReuseIdentifier: cellClass.reuseIdentifier) } + func unregisterClassForCell(_ cellClass: UITableViewCell.Type) { + let registeredClass: UITableViewCell.Type? = nil + register(registeredClass, forCellReuseIdentifier: cellClass.reuseIdentifier) + } + func registerClassesForCell(_ cellClasses: [UITableViewCell.Type]) { cellClasses.forEach { cellClass in register(cellClass, forCellReuseIdentifier: cellClass.reuseIdentifier) @@ -15,6 +20,11 @@ extension UITableView { register(viewClass, forHeaderFooterViewReuseIdentifier: viewClass.reuseIdentifier) } + func unregisterHeaderFooterView(withClass viewClass: UITableViewHeaderFooterView.Type) { + let registeredView: UITableViewHeaderFooterView.Type? = nil + register(registeredView, forHeaderFooterViewReuseIdentifier: viewClass.reuseIdentifier) + } + func dequeueReusableCellWithType(_ cellClass: T.Type) -> T? { dequeueReusableCell(withIdentifier: cellClass.reuseIdentifier) as? T } diff --git a/novawallet/Modules/MainTabBar/MainTabBarInteractor.swift b/novawallet/Modules/MainTabBar/MainTabBarInteractor.swift index e769bda296..c1c9a1bc79 100644 --- a/novawallet/Modules/MainTabBar/MainTabBarInteractor.swift +++ b/novawallet/Modules/MainTabBar/MainTabBarInteractor.swift @@ -49,7 +49,6 @@ extension MainTabBarInteractor: MainTabBarInteractorInputProtocol { extension MainTabBarInteractor: EventVisitorProtocol { func processSelectedAccountChanged(event _: SelectedAccountChanged) { serviceCoordinator.updateOnAccountChange() - presenter?.didReloadSelectedAccount() } } diff --git a/novawallet/Modules/MainTabBar/MainTabBarPresenter.swift b/novawallet/Modules/MainTabBar/MainTabBarPresenter.swift index 2c4d090f9b..4fcfc9a910 100644 --- a/novawallet/Modules/MainTabBar/MainTabBarPresenter.swift +++ b/novawallet/Modules/MainTabBar/MainTabBarPresenter.swift @@ -15,10 +15,6 @@ extension MainTabBarPresenter: MainTabBarPresenterProtocol { } extension MainTabBarPresenter: MainTabBarInteractorOutputProtocol { - func didReloadSelectedAccount() { - wireframe.showNewCrowdloan(on: view) - } - func didRequestImportAccount() { wireframe.presentAccountImport(on: view) } diff --git a/novawallet/Modules/MainTabBar/MainTabBarProtocol.swift b/novawallet/Modules/MainTabBar/MainTabBarProtocol.swift index fa2a6f7f16..52347371c3 100644 --- a/novawallet/Modules/MainTabBar/MainTabBarProtocol.swift +++ b/novawallet/Modules/MainTabBar/MainTabBarProtocol.swift @@ -15,17 +15,13 @@ protocol MainTabBarInteractorInputProtocol: AnyObject { } protocol MainTabBarInteractorOutputProtocol: AnyObject { - func didReloadSelectedAccount() func didRequestImportAccount() } protocol MainTabBarWireframeProtocol: AlertPresentable, AuthorizationAccessible { - func showNewCrowdloan(on view: MainTabBarViewProtocol?) - func presentAccountImport(on view: MainTabBarViewProtocol?) } protocol MainTabBarViewFactoryProtocol: AnyObject { static func createView() -> MainTabBarViewProtocol? - static func reloadCrowdloanView(on view: MainTabBarViewProtocol) } diff --git a/novawallet/Modules/MainTabBar/MainTabBarViewFactory.swift b/novawallet/Modules/MainTabBar/MainTabBarViewFactory.swift index 6455caa595..846badfa42 100644 --- a/novawallet/Modules/MainTabBar/MainTabBarViewFactory.swift +++ b/novawallet/Modules/MainTabBar/MainTabBarViewFactory.swift @@ -33,10 +33,7 @@ final class MainTabBarViewFactory: MainTabBarViewFactoryProtocol { return nil } - guard let crowdloanController = createVoteController( - for: localizationManager, - state: CrowdloanSharedState() - ) else { + guard let voteController = createVoteController(for: localizationManager) else { return nil } @@ -51,7 +48,7 @@ final class MainTabBarViewFactory: MainTabBarViewFactoryProtocol { let view = MainTabBarViewController() view.viewControllers = [ walletController, - crowdloanController, + voteController, dappsController, stakingController, settingsController @@ -70,19 +67,6 @@ final class MainTabBarViewFactory: MainTabBarViewFactoryProtocol { return view } - static func reloadCrowdloanView(on view: MainTabBarViewProtocol) { - let localizationManager = LocalizationManager.shared - - guard let crowdloanController = createVoteController( - for: localizationManager, - state: CrowdloanSharedState() - ) else { - return - } - - view.didReplaceView(for: crowdloanController, for: Self.crowdloanIndex) - } - static func createWalletController( for localizationManager: LocalizationManagerProtocol ) -> UIViewController? { @@ -189,15 +173,12 @@ final class MainTabBarViewFactory: MainTabBarViewFactoryProtocol { return navigationController } - static func createVoteController( - for localizationManager: LocalizationManagerProtocol, - state: CrowdloanSharedState - ) -> UIViewController? { - guard let crowloanView = CrowdloanListViewFactory.createView(with: state) else { + static func createVoteController(for localizationManager: LocalizationManagerProtocol) -> UIViewController? { + guard let view = VoteViewFactory.createView() else { return nil } - let navigationController = FearlessNavigationController(rootViewController: crowloanView.controller) + let navigationController = FearlessNavigationController(rootViewController: view.controller) let localizableTitle = LocalizableResource { locale in R.string.localizable.tabbarVoteTitle(preferredLanguages: locale.rLanguages) diff --git a/novawallet/Modules/MainTabBar/MainTabBarWireframe.swift b/novawallet/Modules/MainTabBar/MainTabBarWireframe.swift index 629a33a37a..aaeda2aaf0 100644 --- a/novawallet/Modules/MainTabBar/MainTabBarWireframe.swift +++ b/novawallet/Modules/MainTabBar/MainTabBarWireframe.swift @@ -2,12 +2,6 @@ import Foundation import CommonWallet final class MainTabBarWireframe: MainTabBarWireframeProtocol { - func showNewCrowdloan(on view: MainTabBarViewProtocol?) { - if let view = view { - MainTabBarViewFactory.reloadCrowdloanView(on: view) - } - } - func presentAccountImport(on view: MainTabBarViewProtocol?) { guard let tabBarController = view?.controller else { return diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift index 4ac0f6106a..51e4e9f7db 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift @@ -1,6 +1,8 @@ import SoraFoundation protocol CrowdloansViewProtocol: AlertPresentable, ControllerBackedProtocol, LoadableViewProtocol { + var presenter: CrowdloanListPresenterProtocol? { get set } + func didReceive(chainInfo: CrowdloansChainViewModel) func didReceive(listState: CrowdloanListState) } @@ -36,7 +38,7 @@ protocol CrowdloanListInteractorOutputProtocol: AnyObject { protocol CrowdloanListWireframeProtocol: AlertPresentable, NoAccountSupportPresentable { func presentContributionSetup( - from view: ControllerBackedProtocol?, + from view: (ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo? ) diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewFactory.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewFactory.swift deleted file mode 100644 index 489abc6941..0000000000 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewFactory.swift +++ /dev/null @@ -1,94 +0,0 @@ -import Foundation -import SoraFoundation -import SubstrateSdk -import SoraKeystore -import IrohaCrypto -import RobinHood - -struct CrowdloanListViewFactory { - static func createView(with sharedState: CrowdloanSharedState) -> CrowdloanListViewProtocol? { - guard let interactor = createInteractor(from: sharedState), - let currencyManager = CurrencyManager.shared else { - return nil - } - - let wireframe = CrowdloanListWireframe(state: sharedState) - - let localizationManager = LocalizationManager.shared - - let viewModelFactory = CrowdloansViewModelFactory( - amountFormatterFactory: AssetBalanceFormatterFactory(), - balanceViewModelFactoryFacade: BalanceViewModelFactoryFacade( - priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) - ) - ) - - let presenter = CrowdloanListPresenter( - interactor: interactor, - wireframe: wireframe, - viewModelFactory: viewModelFactory, - localizationManager: localizationManager, - crowdloansCalculator: CrowdloansCalculator(), - accountManagementFilter: AccountManagementFilter(), - logger: Logger.shared - ) - - let view = CrowdloanListViewController( - presenter: presenter, - localizationManager: localizationManager - ) - - presenter.view = view - interactor.presenter = presenter - - return view - } - - private static func createInteractor( - from state: CrowdloanSharedState - ) -> CrowdloanListInteractor? { - guard - let currencyManager = CurrencyManager.shared, - let selectedMetaAccount = SelectedWalletSettings.shared.value else { - return nil - } - - let chainRegistry = ChainRegistryFacade.sharedRegistry - let repository = SubstrateRepositoryFactory().createChainStorageItemRepository() - - let operationManager = OperationManagerFacade.sharedManager - let logger = Logger.shared - - let crowdloanRemoteSubscriptionService = CrowdloanRemoteSubscriptionService( - chainRegistry: chainRegistry, - repository: AnyDataProviderRepository(repository), - operationManager: operationManager, - logger: logger - ) - - let storageRequestFactory = StorageRequestFactory( - remoteFactory: StorageKeyFactory(), - operationManager: operationManager - ) - - let crowdloanOperationFactory = CrowdloanOperationFactory( - requestOperationFactory: storageRequestFactory, - operationManager: operationManager - ) - - return CrowdloanListInteractor( - selectedMetaAccount: selectedMetaAccount, - crowdloanState: state, - chainRegistry: chainRegistry, - crowdloanOperationFactory: crowdloanOperationFactory, - crowdloanRemoteSubscriptionService: crowdloanRemoteSubscriptionService, - walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, - jsonDataProviderFactory: JsonDataProviderFactory.shared, - operationManager: operationManager, - applicationHandler: ApplicationHandler(), - currencyManager: currencyManager, - priceLocalSubscriptionFactory: PriceProviderFactory.shared, - logger: logger - ) - } -} diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewLayout.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewLayout.swift deleted file mode 100644 index 905e85ee20..0000000000 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewLayout.swift +++ /dev/null @@ -1,59 +0,0 @@ -import UIKit -import SnapKit - -final class CrowdloanListViewLayout: UIView { - private let backgroundView = MultigradientView.background - - let headerView = CrowdloanTableHeaderView() - - let tableView: UITableView = { - let view = UITableView() - view.backgroundColor = .clear - view.separatorColor = R.color.colorDarkGray() - view.refreshControl = UIRefreshControl() - view.tableFooterView = UIView() - view.separatorStyle = .none - view.contentInset = .init(top: 0, left: 0, bottom: 16, right: 0) - return view - }() - - override init(frame: CGRect) { - super.init(frame: frame) - - setup() - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - - let height = headerView.systemLayoutSizeFitting( - CGSize(width: bounds.size.width, height: UIView.layoutFittingExpandedSize.height) - ).height - - var headerFrame = headerView.frame - - // Comparison necessary to avoid infinite loop - if height != headerFrame.size.height { - headerFrame.size.height = height - headerView.frame = headerFrame - tableView.tableHeaderView = headerView - } - } - - private func setup() { - addSubview(backgroundView) - backgroundView.snp.makeConstraints { $0.edges.equalToSuperview() } - - addSubview(tableView) - tableView.snp.makeConstraints { make in - make.top.equalToSuperview() - make.leading.bottom.trailing.equalToSuperview() - } - tableView.tableHeaderView = headerView - } -} diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift index a20dad8b58..172cf6b76e 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift @@ -8,7 +8,7 @@ final class CrowdloanListViewManager: NSObject { var locale = Locale.current - private weak var presenter: CrowdloanListPresenterProtocol? + weak var presenter: CrowdloanListPresenterProtocol? private weak var parent: ControllerBackedProtocol? private var state: CrowdloanListState = .loading @@ -19,9 +19,6 @@ final class CrowdloanListViewManager: NSObject { self.parent = parent super.init() - - tableView.delegate = self - tableView.dataSource = self } } @@ -189,4 +186,32 @@ extension CrowdloanListViewManager: VoteChildViewProtocol { var controller: UIViewController { parent?.controller ?? UIViewController() } + + func bind() { + tableView.registerClassForCell(YourContributionsTableViewCell.self) + tableView.registerClassForCell(AboutCrowdloansTableViewCell.self) + tableView.registerClassForCell(CrowdloanTableViewCell.self) + tableView.registerClassForCell(BlurredTableViewCell.self) + tableView.registerClassForCell(BlurredTableViewCell.self) + tableView.registerHeaderFooterView(withClass: CrowdloanStatusSectionView.self) + + tableView.dataSource = self + tableView.delegate = self + + tableView.reloadData() + } + + func unbind() { + tableView.unregisterClassForCell(YourContributionsTableViewCell.self) + tableView.unregisterClassForCell(AboutCrowdloansTableViewCell.self) + tableView.unregisterClassForCell(CrowdloanTableViewCell.self) + tableView.unregisterClassForCell(BlurredTableViewCell.self) + tableView.unregisterClassForCell(BlurredTableViewCell.self) + tableView.unregisterHeaderFooterView(withClass: CrowdloanStatusSectionView.self) + + tableView.dataSource = nil + tableView.delegate = nil + + tableView.reloadData() + } } diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift index a08ee3f9e9..8807182717 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListWireframe.swift @@ -18,7 +18,7 @@ final class CrowdloanListWireframe: CrowdloanListWireframeProtocol { } func presentContributionSetup( - from view: ControllerBackedProtocol?, + from view: (ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo? ) { diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift index 1df95f1a61..f1938bddec 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift @@ -16,6 +16,7 @@ extension CrowdloanListInteractor: CrowdloanListInteractorInputProtocol { let accountId = selectedMetaAccount.fetch(for: chain.accountRequest())?.accountId setup(with: accountId, chain: chain) + becomeOnline(with: chain) } func setup() { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift new file mode 100644 index 0000000000..416e574e8b --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -0,0 +1,7 @@ +import Foundation + +final class ReferendumsInteractor { + weak var presenter: ReferendumsInteractorOutputProtocol? +} + +extension ReferendumsInteractor: ReferendumsInteractorInputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift new file mode 100644 index 0000000000..94e74ec922 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -0,0 +1,30 @@ +import Foundation + +final class ReferendumsPresenter { + weak var view: ReferendumsViewProtocol? + + let interactor: ReferendumsInteractorInputProtocol + let wireframe: ReferendumsWireframeProtocol + + init( + interactor: ReferendumsInteractorInputProtocol, + wireframe: ReferendumsWireframeProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + } +} + +extension ReferendumsPresenter: ReferendumsPresenterProtocol {} + +extension ReferendumsPresenter: VoteChildPresenterProtocol { + func setup() {} + + func becomeOnline() {} + + func putOffline() {} + + func selectChain() {} +} + +extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 66c5c8ab86..62aef6c5fb 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -1,3 +1,13 @@ import Foundation -protocol ReferendumsViewProtocol: AnyObject {} +protocol ReferendumsViewProtocol: AnyObject { + var presenter: ReferendumsPresenterProtocol? { get set } +} + +protocol ReferendumsPresenterProtocol: AnyObject {} + +protocol ReferendumsInteractorInputProtocol: AnyObject {} + +protocol ReferendumsInteractorOutputProtocol: AnyObject {} + +protocol ReferendumsWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 2b85055e1e..572d389d51 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -1,16 +1,48 @@ import Foundation import UIKit -final class ReferendumsViewManager { +final class ReferendumsViewManager: NSObject { let tableView: UITableView var locale = Locale.current + weak var presenter: ReferendumsPresenterProtocol? private weak var parent: ControllerBackedProtocol? init(tableView: UITableView, parent: ControllerBackedProtocol) { self.tableView = tableView self.parent = parent + + super.init() + } +} + +// TODO: Implement protocols when data source defined +extension ReferendumsViewManager: UITableViewDataSource { + func numberOfSections(in _: UITableView) -> Int { + 0 + } + + func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + 0 + } + + func tableView(_: UITableView, cellForRowAt _: IndexPath) -> UITableViewCell { + UITableViewCell() + } +} + +extension ReferendumsViewManager: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + } + + func tableView(_: UITableView, viewForHeaderInSection _: Int) -> UIView? { + nil + } + + func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat { + 0.0 } } @@ -24,4 +56,18 @@ extension ReferendumsViewManager: VoteChildViewProtocol { var controller: UIViewController { parent?.controller ?? UIViewController() } + + func bind() { + tableView.dataSource = self + tableView.delegate = self + + tableView.reloadData() + } + + func unbind() { + tableView.dataSource = nil + tableView.delegate = nil + + tableView.reloadData() + } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift new file mode 100644 index 0000000000..5b26e53c21 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class ReferendumsWireframe: ReferendumsWireframeProtocol {} diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index 49d3f97697..8df9e6128c 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -95,7 +95,7 @@ final class VoteChildPresenterFactory { extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { func createCrowdloanPresenter( - from _: CrowdloansViewProtocol, + from view: CrowdloansViewProtocol, wallet: MetaAccountModel ) -> VoteChildPresenterProtocol? { let state = CrowdloanSharedState() @@ -121,11 +121,26 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { logger: Logger.shared ) + presenter.view = view + view.presenter = presenter + interactor.presenter = presenter + return presenter } func createGovernancePresenter( - from _: ReferendumsViewProtocol, + from view: ReferendumsViewProtocol, wallet _: MetaAccountModel - ) -> VoteChildPresenterProtocol? {} + ) -> VoteChildPresenterProtocol? { + let interactor = ReferendumsInteractor() + let wireframe = ReferendumsWireframe() + + let presenter = ReferendumsPresenter(interactor: interactor, wireframe: wireframe) + + presenter.view = view + view.presenter = presenter + interactor.presenter = presenter + + return presenter + } } diff --git a/novawallet/Modules/Vote/Parent/VoteInteractor.swift b/novawallet/Modules/Vote/Parent/VoteInteractor.swift index 50d9784303..948e33808b 100644 --- a/novawallet/Modules/Vote/Parent/VoteInteractor.swift +++ b/novawallet/Modules/Vote/Parent/VoteInteractor.swift @@ -27,7 +27,7 @@ extension VoteInteractor: VoteInteractorInputProtocol { func setup() { provideSelectedWallet() - eventCenter.add(observer: self) + eventCenter.add(observer: self, dispatchIn: .main) } } diff --git a/novawallet/Modules/Vote/Parent/VotePresenter.swift b/novawallet/Modules/Vote/Parent/VotePresenter.swift index 02beee21f0..40b0269293 100644 --- a/novawallet/Modules/Vote/Parent/VotePresenter.swift +++ b/novawallet/Modules/Vote/Parent/VotePresenter.swift @@ -58,6 +58,7 @@ extension VotePresenter: VotePresenterProtocol { return } + childPresenter?.putOffline() childPresenter = childPresenterFactory.createGovernancePresenter(from: view, wallet: wallet) childPresenter?.setup() } @@ -67,6 +68,7 @@ extension VotePresenter: VotePresenterProtocol { return } + childPresenter?.putOffline() childPresenter = childPresenterFactory.createCrowdloanPresenter(from: view, wallet: wallet) childPresenter?.setup() } diff --git a/novawallet/Modules/Vote/Parent/VoteProtocols.swift b/novawallet/Modules/Vote/Parent/VoteProtocols.swift index 0d6b4d1983..1a4836824d 100644 --- a/novawallet/Modules/Vote/Parent/VoteProtocols.swift +++ b/novawallet/Modules/Vote/Parent/VoteProtocols.swift @@ -35,6 +35,9 @@ protocol VoteWireframeProtocol: AlertPresentable, ErrorPresentable, WalletSwitch protocol VoteChildViewProtocol: ControllerBackedProtocol { var locale: Locale { get set } + + func bind() + func unbind() } protocol VoteChildPresenterProtocol: AnyObject { diff --git a/novawallet/Modules/Vote/Parent/VoteViewController.swift b/novawallet/Modules/Vote/Parent/VoteViewController.swift index 5f7dd76c5c..3d40a0dfc4 100644 --- a/novawallet/Modules/Vote/Parent/VoteViewController.swift +++ b/novawallet/Modules/Vote/Parent/VoteViewController.swift @@ -30,7 +30,7 @@ final class VoteViewController: UIViewController, ViewHolder { } override func loadView() { - view = CrowdloanListViewLayout() + view = VoteViewLayout() } override func viewDidLoad() { @@ -94,6 +94,9 @@ final class VoteViewController: UIViewController, ViewHolder { } private func setupChildView() { + childView?.unbind() + childView = nil + switch selectedType { case .governance: let governanceChildView = ReferendumsViewManager( @@ -102,6 +105,8 @@ final class VoteViewController: UIViewController, ViewHolder { ) childView = governanceChildView + childView?.bind() + childView?.locale = selectedLocale presenter.switchToGovernance(governanceChildView) case .crowdloan: @@ -110,12 +115,13 @@ final class VoteViewController: UIViewController, ViewHolder { chainSelectionView: rootView.headerView, parent: self ) + childView = crowdloanChildView + childView?.bind() + childView?.locale = selectedLocale presenter.switchToCrowdloans(crowdloanChildView) } - - childView?.locale = selectedLocale } } @@ -134,3 +140,5 @@ extension VoteViewController: Localizable { } } } + +extension VoteViewController: HiddableBarWhenPushed {} diff --git a/novawallet/Modules/Vote/Parent/VoteViewFactory.swift b/novawallet/Modules/Vote/Parent/VoteViewFactory.swift new file mode 100644 index 0000000000..728f9edf5e --- /dev/null +++ b/novawallet/Modules/Vote/Parent/VoteViewFactory.swift @@ -0,0 +1,32 @@ +import Foundation +import SoraFoundation + +enum VoteViewFactory { + static func createView() -> VoteViewProtocol? { + guard let currencyManager = CurrencyManager.shared else { + return nil + } + + let interactor = VoteInteractor( + walletSettings: SelectedWalletSettings.shared, + eventCenter: EventCenter.shared + ) + + let wireframe = VoteWireframe() + + let childPresenterFactory = VoteChildPresenterFactory(currencyManager: currencyManager) + + let presenter = VotePresenter( + interactor: interactor, + wireframe: wireframe, + childPresenterFactory: childPresenterFactory + ) + + let view = VoteViewController(presenter: presenter, localizationManager: LocalizationManager.shared) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} diff --git a/novawallet/Modules/Vote/Parent/VoteViewLayout.swift b/novawallet/Modules/Vote/Parent/VoteViewLayout.swift index 36194f3483..8f90b7301c 100644 --- a/novawallet/Modules/Vote/Parent/VoteViewLayout.swift +++ b/novawallet/Modules/Vote/Parent/VoteViewLayout.swift @@ -10,7 +10,6 @@ final class VoteViewLayout: UIView, TableHeaderLayoutUpdatable { let view = UITableView() view.backgroundColor = .clear view.separatorColor = R.color.colorDarkGray() - view.refreshControl = UIRefreshControl() view.tableFooterView = UIView() view.separatorStyle = .none view.contentInset = .init(top: 0, left: 0, bottom: 16, right: 0) @@ -43,6 +42,7 @@ final class VoteViewLayout: UIView, TableHeaderLayoutUpdatable { make.top.equalToSuperview() make.leading.bottom.trailing.equalToSuperview() } + tableView.tableHeaderView = headerView } } From c24e1991d8e27186781f0e5491b4f153cf8956f4 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 4 Oct 2022 00:46:46 +0500 Subject: [PATCH 009/229] add crowdloans option to entity --- novawallet.xcodeproj/project.pbxproj | 56 +++++- .../Common/Extension/SettingsExtension.swift | 15 ++ .../Migration/SubstrateStorageVersion.swift | 3 + .../Model/ChainRegistry/ChainModel.swift | 4 + .../EntityToModel/ChainModelMapper.swift | 5 + .../Storage/GovernanceChainSettings.swift | 74 ++++++++ .../.xccurrentversion | 2 +- .../SubstrateDataModel3.xcdatamodel/contents | 165 ++++++++++++++++++ .../Storage/SubstrateDataStorageFacade.swift | 2 +- .../ViewModel/ChainBalanceViewModel.swift | 7 + .../ChainBalanceViewModelFactory.swift | 29 +++ .../CrowdloanListPresenter.swift | 9 +- .../CrowdloanListProtocols.swift | 2 +- .../CrowdloanListViewManager.swift | 2 +- .../CrowdloansViewModelFactory.swift | 41 ----- .../Model/GovernanceSharedState.swift | 13 ++ .../Model/ReferendumsInteractorError.swift | 8 + .../Referendums/ReferendumsInteractor.swift | 148 +++++++++++++++- .../Referendums/ReferendumsPresenter.swift | 88 +++++++++- .../Referendums/ReferendumsProtocols.swift | 24 ++- .../Referendums/ReferendumsViewManager.swift | 10 +- .../Referendums/ReferendumsWireframe.swift | 26 ++- .../View/VoteTableHeaderView.swift} | 14 +- .../Parent/VoteChildPresenterFactory.swift | 25 ++- .../Modules/Vote/Parent/VoteProtocols.swift | 2 +- .../Vote/Parent/VoteViewController.swift | 1 + .../Modules/Vote/Parent/VoteViewLayout.swift | 2 +- 27 files changed, 698 insertions(+), 79 deletions(-) create mode 100644 novawallet/Common/Storage/GovernanceChainSettings.swift create mode 100644 novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel3.xcdatamodel/contents create mode 100644 novawallet/Common/ViewModel/ChainBalanceViewModel.swift create mode 100644 novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift create mode 100644 novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift rename novawallet/Modules/Vote/{Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift => Parent/View/VoteTableHeaderView.swift} (87%) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index b08331f87c..9d3044d2ac 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1823,6 +1823,11 @@ 84D6D7FC27A7F4B40094FC33 /* AssetListNetworkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D6D7FB27A7F4B40094FC33 /* AssetListNetworkView.swift */; }; 84D6D7FE27A7F4CD0094FC33 /* AssetListChainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D6D7FD27A7F4CD0094FC33 /* AssetListChainView.swift */; }; 84D6E2FA283AE6590031D6FD /* ExtrinsicSubmissionPresenting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D6E2F9283AE6590031D6FD /* ExtrinsicSubmissionPresenting.swift */; }; + 84D8753A28EB0A93004065BD /* GovernanceChainSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8753928EB0A93004065BD /* GovernanceChainSettings.swift */; }; + 84D8753D28EB17B2004065BD /* GovernanceSharedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8753C28EB17B2004065BD /* GovernanceSharedState.swift */; }; + 84D8754028EB1A59004065BD /* ReferendumsInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8753F28EB1A59004065BD /* ReferendumsInteractorError.swift */; }; + 84D8754228EB5D66004065BD /* ChainBalanceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8754128EB5D66004065BD /* ChainBalanceViewModel.swift */; }; + 84D8754428EB5E6D004065BD /* ChainBalanceViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8754328EB5E6D004065BD /* ChainBalanceViewModelFactory.swift */; }; 84D8F15524D80CA100AF43E9 /* ModalPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8F15424D80CA100AF43E9 /* ModalPickerViewController.swift */; }; 84D8F15724D80D5500AF43E9 /* ModalPickerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84D8F15624D80D5500AF43E9 /* ModalPickerViewController.xib */; }; 84D8F15B24D8136700AF43E9 /* ModalPickerCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8F15A24D8136700AF43E9 /* ModalPickerCellProtocol.swift */; }; @@ -2719,7 +2724,7 @@ F4F65C3326D8B81A002EE838 /* FWChartViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F65C3226D8B81A002EE838 /* FWChartViewProtocol.swift */; }; F4F65C3826D8B86F002EE838 /* FWXAxisEmptyValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F65C3726D8B86F002EE838 /* FWXAxisEmptyValueFormatter.swift */; }; F4F65C3D26D8B9DD002EE838 /* FWYAxisChartFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F65C3C26D8B9DD002EE838 /* FWYAxisChartFormatter.swift */; }; - F4F69E282731B0B200214542 /* CrowdloanTableHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F69E272731B0B200214542 /* CrowdloanTableHeaderView.swift */; }; + F4F69E282731B0B200214542 /* VoteTableHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F69E272731B0B200214542 /* VoteTableHeaderView.swift */; }; F4FDA0F826A57626003D753B /* BabeEraOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FDA0F726A57626003D753B /* BabeEraOperationFactory.swift */; }; F4FDA0FD26A57860003D753B /* EraCountdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FDA0FC26A57860003D753B /* EraCountdown.swift */; }; F5CA222FA684AAC8B556E667 /* DAppAddFavoritePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F599B3A847492204853ADB /* DAppAddFavoritePresenter.swift */; }; @@ -4608,6 +4613,12 @@ 84D6D7FB27A7F4B40094FC33 /* AssetListNetworkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListNetworkView.swift; sourceTree = ""; }; 84D6D7FD27A7F4CD0094FC33 /* AssetListChainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListChainView.swift; sourceTree = ""; }; 84D6E2F9283AE6590031D6FD /* ExtrinsicSubmissionPresenting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicSubmissionPresenting.swift; sourceTree = ""; }; + 84D8753928EB0A93004065BD /* GovernanceChainSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceChainSettings.swift; sourceTree = ""; }; + 84D8753C28EB17B2004065BD /* GovernanceSharedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceSharedState.swift; sourceTree = ""; }; + 84D8753F28EB1A59004065BD /* ReferendumsInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsInteractorError.swift; sourceTree = ""; }; + 84D8754128EB5D66004065BD /* ChainBalanceViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainBalanceViewModel.swift; sourceTree = ""; }; + 84D8754328EB5E6D004065BD /* ChainBalanceViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainBalanceViewModelFactory.swift; sourceTree = ""; }; + 84D8754628EB726E004065BD /* SubstrateDataModel3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SubstrateDataModel3.xcdatamodel; sourceTree = ""; }; 84D8F15424D80CA100AF43E9 /* ModalPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalPickerViewController.swift; sourceTree = ""; }; 84D8F15624D80D5500AF43E9 /* ModalPickerViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ModalPickerViewController.xib; sourceTree = ""; }; 84D8F15A24D8136700AF43E9 /* ModalPickerCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalPickerCellProtocol.swift; sourceTree = ""; }; @@ -5499,7 +5510,7 @@ F4F65C3226D8B81A002EE838 /* FWChartViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FWChartViewProtocol.swift; sourceTree = ""; }; F4F65C3726D8B86F002EE838 /* FWXAxisEmptyValueFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FWXAxisEmptyValueFormatter.swift; sourceTree = ""; }; F4F65C3C26D8B9DD002EE838 /* FWYAxisChartFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FWYAxisChartFormatter.swift; sourceTree = ""; }; - F4F69E272731B0B200214542 /* CrowdloanTableHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrowdloanTableHeaderView.swift; sourceTree = ""; }; + F4F69E272731B0B200214542 /* VoteTableHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoteTableHeaderView.swift; sourceTree = ""; }; F4F9944B0577EFF25A0643FE /* LocksProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LocksProtocols.swift; sourceTree = ""; }; F4FDA0F726A57626003D753B /* BabeEraOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BabeEraOperationFactory.swift; sourceTree = ""; }; F4FDA0FC26A57860003D753B /* EraCountdown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EraCountdown.swift; sourceTree = ""; }; @@ -7350,6 +7361,7 @@ 8442002128E6FE0100C49C4A /* Referendums */ = { isa = PBXGroup; children = ( + 84D8753E28EB1A46004065BD /* Model */, 8442002228E6FE1E00C49C4A /* ReferendumsViewManager.swift */, 8442002428E6FEEE00C49C4A /* ReferendumsProtocols.swift */, 8442003728EAA16600C49C4A /* ReferendumsPresenter.swift */, @@ -7853,6 +7865,7 @@ 845B822826F0BB6700D25C72 /* CrowdloanChainSettings.swift */, 84F13F0726F13898006725FF /* StakingAssetSettings.swift */, 841AAC2E26F73E0C00F0A25E /* LocalStorageKeyFactory.swift */, + 84D8753928EB0A93004065BD /* GovernanceChainSettings.swift */, ); path = Storage; sourceTree = ""; @@ -7896,6 +7909,7 @@ 8468119828E6D2A400BF54F1 /* Parent */ = { isa = PBXGroup; children = ( + 84D8754528EB6B7A004065BD /* View */, 8468119628E6C90F00BF54F1 /* VoteProtocols.swift */, 8442002628E6FFBA00C49C4A /* VoteViewController.swift */, 8442002828E7004B00C49C4A /* VoteViewLayout.swift */, @@ -8223,6 +8237,7 @@ 847A25C028D84A3D006AC9F5 /* Governance */ = { isa = PBXGroup; children = ( + 84D8753B28EB1796004065BD /* Model */, 8442002128E6FE0100C49C4A /* Referendums */, ); path = Governance; @@ -9381,6 +9396,8 @@ 84E2589C2892B41500DC8A51 /* WalletSwitchViewModelFactory.swift */, 845E49822636C87B002F8C22 /* ActionManageViewModel.swift */, 84BC704A289F1338008A9758 /* ExpirationTimeViewModel.swift */, + 84D8754128EB5D66004065BD /* ChainBalanceViewModel.swift */, + 84D8754328EB5E6D004065BD /* ChainBalanceViewModelFactory.swift */, ); path = ViewModel; sourceTree = ""; @@ -9520,7 +9537,6 @@ isa = PBXGroup; children = ( 88E8CF5D28E3789600C90112 /* CrowdloanEmptyView.swift */, - F4F69E272731B0B200214542 /* CrowdloanTableHeaderView.swift */, 84BB3CF7267D276D00676FFE /* CrowdloanTableViewCell.swift */, 8498430226592D29006BBB9F /* CrowdloanStatusSectionView.swift */, 88D997B128ABC90E006135A5 /* AboutCrowdloansView.swift */, @@ -10928,6 +10944,30 @@ path = Parachain; sourceTree = ""; }; + 84D8753B28EB1796004065BD /* Model */ = { + isa = PBXGroup; + children = ( + 84D8753C28EB17B2004065BD /* GovernanceSharedState.swift */, + ); + path = Model; + sourceTree = ""; + }; + 84D8753E28EB1A46004065BD /* Model */ = { + isa = PBXGroup; + children = ( + 84D8753F28EB1A59004065BD /* ReferendumsInteractorError.swift */, + ); + path = Model; + sourceTree = ""; + }; + 84D8754528EB6B7A004065BD /* View */ = { + isa = PBXGroup; + children = ( + F4F69E272731B0B200214542 /* VoteTableHeaderView.swift */, + ); + path = View; + sourceTree = ""; + }; 84D8F15324D80C8300AF43E9 /* ModalPicker */ = { isa = PBXGroup; children = ( @@ -14164,6 +14204,7 @@ 8411707A285B10F5006F4DFB /* XcmAssetTransferFee.swift in Sources */, 84DBEA56265ED62700FDF73C /* BaseErrorPresentable.swift in Sources */, 842876B224AE059700D91AD8 /* SupportData.swift in Sources */, + 84D8754228EB5D66004065BD /* ChainBalanceViewModel.swift in Sources */, 84893C0524DA8663008F6A3F /* AccountCreationError.swift in Sources */, 84282FBD26D05A54002CA322 /* ChainRegistryFacade.swift in Sources */, 842EBB3B2890B06500B952D8 /* WalletSelectionPresenter.swift in Sources */, @@ -14240,7 +14281,7 @@ 8446F5FA28192FF500B7A86C /* ListLoadingView.swift in Sources */, 844384AC28538D3000611CE2 /* RewardCalculatorEngine.swift in Sources */, 84DBEA5E265EDAD300FDF73C /* BaseDataValidatorFactory.swift in Sources */, - F4F69E282731B0B200214542 /* CrowdloanTableHeaderView.swift in Sources */, + F4F69E282731B0B200214542 /* VoteTableHeaderView.swift in Sources */, 8428768624AE046300D91AD8 /* LanguageSelectionPresenter.swift in Sources */, 8490152724ABCC40008F705E /* NumberFormatter.swift in Sources */, 846A2C4325271CDE00731018 /* TransactionType.swift in Sources */, @@ -14749,6 +14790,7 @@ 84F43BAA25DEB75000AEDA56 /* StakingMainViewModel.swift in Sources */, 84DD5F35263D86EF00425ACF /* AccountFetching.swift in Sources */, 84E172D128BF383B00DC85B6 /* Array+Dictionary.swift in Sources */, + 84D8754028EB1A59004065BD /* ReferendumsInteractorError.swift in Sources */, 849AFEB726DBC0BE00B65924 /* AssetTransactionData+HistoryItemData.swift in Sources */, 849014A624AA801B008F705E /* TextSharingSource.swift in Sources */, 840AD5FC26B4512100E09D6A /* SelectedLanguageMigrator.swift in Sources */, @@ -15077,6 +15119,7 @@ 8466781127EB4078007935D3 /* StackNetworkFeeCell.swift in Sources */, 8D9BC9C36DC891CDD900A895 /* AccountConfirmViewController.swift in Sources */, 84222986283621F2009F0086 /* StakingRewardInfoViewModel.swift in Sources */, + 84D8754428EB5E6D004065BD /* ChainBalanceViewModelFactory.swift in Sources */, E14F809C3917EFA4B5388AC8 /* AccountConfirmViewFactory.swift in Sources */, 842A738027DCD427006EE1EA /* OperationDetailsRewardView.swift in Sources */, 9D5926790B055C56FB74B282 /* AccountManagementProtocols.swift in Sources */, @@ -15093,6 +15136,7 @@ 84754CA42513E6DC00854599 /* PrimitiveContextWrapper.swift in Sources */, 848B3000286EDE3800465BA2 /* ParaIdOperationFactory.swift in Sources */, 84F47D4B2666EF1C00F7647A /* KaruraStatementData.swift in Sources */, + 84D8753A28EB0A93004065BD /* GovernanceChainSettings.swift in Sources */, 8443FE24255586230092893D /* ExportMnemonicConfirmProtocols.swift in Sources */, 84644A0C256713D5004EAA4B /* TriangularedBlurView+Inspectable.swift in Sources */, 849A4EF6279A7AEF00AB6709 /* StateminAssetExtras.swift in Sources */, @@ -15114,6 +15158,7 @@ F4A11B5A272FEB0B0030E85B /* CrowdloanYourContributionsCell.swift in Sources */, 848E6BDF276218E600C91022 /* GlowingView.swift in Sources */, 843910B6253EE62B00E3C217 /* DataProviderChange+Result.swift in Sources */, + 84D8753D28EB17B2004065BD /* GovernanceSharedState.swift in Sources */, 8436EDE725895846004D9E97 /* PurchaseProvider.swift in Sources */, AEF50556261A04AD0098574D /* MoonpayProvider.swift in Sources */, 84FB29942639ABD700BE0FCD /* YourValidatorList+SelectionStart.swift in Sources */, @@ -16955,10 +17000,11 @@ 843910CA253F7E6500E3C217 /* SubstrateDataModel.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 84D8754628EB726E004065BD /* SubstrateDataModel3.xcdatamodel */, 88787F0328DB3A7B00B115AB /* SubstrateDataModel2.xcdatamodel */, 843910CB253F7E6500E3C217 /* SubstrateDataModel.xcdatamodel */, ); - currentVersion = 88787F0328DB3A7B00B115AB /* SubstrateDataModel2.xcdatamodel */; + currentVersion = 84D8754628EB726E004065BD /* SubstrateDataModel3.xcdatamodel */; path = SubstrateDataModel.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/novawallet/Common/Extension/SettingsExtension.swift b/novawallet/Common/Extension/SettingsExtension.swift index c4a468aad4..95e44723fc 100644 --- a/novawallet/Common/Extension/SettingsExtension.swift +++ b/novawallet/Common/Extension/SettingsExtension.swift @@ -10,6 +10,7 @@ enum SettingsKey: String { case stakingNetworkExpansion case hidesZeroBalances case selectedCurrency + case governanceChainId } extension SettingsManagerProtocol { @@ -41,6 +42,20 @@ extension SettingsManagerProtocol { } } + var governanceChainId: String? { + get { + string(for: SettingsKey.governanceChainId.rawValue) + } + + set { + if let existingValue = newValue { + set(value: existingValue, for: SettingsKey.governanceChainId.rawValue) + } else { + removeValue(for: SettingsKey.governanceChainId.rawValue) + } + } + } + var stakingAsset: ChainAssetId? { get { value(of: ChainAssetId.self, for: SettingsKey.stakingAsset.rawValue) diff --git a/novawallet/Common/Migration/SubstrateStorageVersion.swift b/novawallet/Common/Migration/SubstrateStorageVersion.swift index 70e23a87f5..1bb0b326bf 100644 --- a/novawallet/Common/Migration/SubstrateStorageVersion.swift +++ b/novawallet/Common/Migration/SubstrateStorageVersion.swift @@ -1,6 +1,7 @@ enum SubstrateStorageVersion: String, CaseIterable { case version1 = "SubstrateDataModel" case version2 = "SubstrateDataModel2" + case version3 = "SubstrateDataModel3" static var current: SubstrateStorageVersion { allCases.last! @@ -11,6 +12,8 @@ enum SubstrateStorageVersion: String, CaseIterable { case .version1: return .version2 case .version2: + return .version3 + case .version3: return nil } } diff --git a/novawallet/Common/Model/ChainRegistry/ChainModel.swift b/novawallet/Common/Model/ChainRegistry/ChainModel.swift index 9fb6ee052c..d55baf9aac 100644 --- a/novawallet/Common/Model/ChainRegistry/ChainModel.swift +++ b/novawallet/Common/Model/ChainRegistry/ChainModel.swift @@ -119,6 +119,10 @@ struct ChainModel: Equatable, Codable, Hashable { options?.contains(.crowdloans) ?? false } + var hasGovernance: Bool { + options?.contains(.governance) ?? false + } + var isRelaychain: Bool { parentId == nil } func utilityAssets() -> Set { diff --git a/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift b/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift index b259f03ee5..34e6fde386 100644 --- a/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift +++ b/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift @@ -254,6 +254,10 @@ extension ChainModelMapper: CoreDataMapperProtocol { options.append(.crowdloans) } + if entity.hasGovernance { + options.append(.governance) + } + let externalApiSet = createExternalApi(from: entity) let explorers = createExplorers(from: entity) @@ -294,6 +298,7 @@ extension ChainModelMapper: CoreDataMapperProtocol { entity.isEthereumBased = model.isEthereumBased entity.isTestnet = model.isTestnet entity.hasCrowdloans = model.hasCrowdloans + entity.hasGovernance = model.hasGovernance entity.order = model.order entity.additional = try model.additional.map { try jsonEncoder.encode($0) diff --git a/novawallet/Common/Storage/GovernanceChainSettings.swift b/novawallet/Common/Storage/GovernanceChainSettings.swift new file mode 100644 index 0000000000..0050182b75 --- /dev/null +++ b/novawallet/Common/Storage/GovernanceChainSettings.swift @@ -0,0 +1,74 @@ +import Foundation +import SoraKeystore +import RobinHood + +final class GovernanceChainSettings: PersistentValueSettings { + let chainRegistry: ChainRegistryProtocol + let settings: SettingsManagerProtocol + + init( + chainRegistry: ChainRegistryProtocol, + settings: SettingsManagerProtocol + ) { + self.chainRegistry = chainRegistry + self.settings = settings + } + + override func performSetup(completionClosure: @escaping (Result) -> Void) { + let maybeChainId = settings.governanceChainId + + var completed: Bool = false + let mutex = NSLock() + + chainRegistry.chainsSubscribe( + self, + runningInQueue: DispatchQueue.global(qos: .userInteractive) + ) { [weak self] changes in + mutex.lock() + + defer { + mutex.unlock() + } + + let chains: [ChainModel] = changes.allChangedItems() + + guard !chains.isEmpty, !completed else { + return + } + + completed = true + + self?.completeSetup(for: chains, currentChainId: maybeChainId, completionClosure: completionClosure) + } + } + + override func performSave( + value: ChainModel, + completionClosure: @escaping (Result + ) -> Void + ) { + settings.governanceChainId = value.chainId + completionClosure(.success(value)) + } + + private func completeSetup( + for chains: [ChainModel], + currentChainId: ChainModel.Id?, + completionClosure: @escaping (Result) -> Void + ) { + let selectedChain: ChainModel? + + if let chain = chains.first(where: { $0.chainId == currentChainId }) { + selectedChain = chain + } else if let firstChain = chains.first(where: { $0.hasGovernance }) { + settings.governanceChainId = firstChain.chainId + selectedChain = firstChain + } else { + selectedChain = nil + } + + chainRegistry.chainsUnsubscribe(self) + + completionClosure(.success(selectedChain)) + } +} diff --git a/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion index 16a19db870..0d3a209131 100644 --- a/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion +++ b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - SubstrateDataModel2.xcdatamodel + SubstrateDataModel3.xcdatamodel diff --git a/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel3.xcdatamodel/contents b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel3.xcdatamodel/contents new file mode 100644 index 0000000000..5e32b56928 --- /dev/null +++ b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel3.xcdatamodel/contents @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/novawallet/Common/Storage/SubstrateDataStorageFacade.swift b/novawallet/Common/Storage/SubstrateDataStorageFacade.swift index 2f131715ef..8932c422d7 100644 --- a/novawallet/Common/Storage/SubstrateDataStorageFacade.swift +++ b/novawallet/Common/Storage/SubstrateDataStorageFacade.swift @@ -4,7 +4,7 @@ import CoreData enum SubstrateStorageParams { static let databaseName = "SubstrateDataModel.sqlite" static let modelDirectory: String = "SubstrateDataModel.momd" - static let modelVersion: SubstrateStorageVersion = .version2 + static let modelVersion: SubstrateStorageVersion = .version3 static let storageDirectoryURL: URL = { let baseURL = FileManager.default.urls( diff --git a/novawallet/Common/ViewModel/ChainBalanceViewModel.swift b/novawallet/Common/ViewModel/ChainBalanceViewModel.swift new file mode 100644 index 0000000000..321421d9b5 --- /dev/null +++ b/novawallet/Common/ViewModel/ChainBalanceViewModel.swift @@ -0,0 +1,7 @@ +import Foundation + +struct ChainBalanceViewModel { + let name: String + let icon: ImageViewModelProtocol + let balance: String? +} diff --git a/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift b/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift new file mode 100644 index 0000000000..1cc322f1f8 --- /dev/null +++ b/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift @@ -0,0 +1,29 @@ +import Foundation +import BigInt + +final class ChainBalanceViewModelFactory { + let formatterFactory: AssetBalanceFormatterFactoryProtocol + + init(formatterFactory: AssetBalanceFormatterFactoryProtocol = AssetBalanceFormatterFactory()) { + self.formatterFactory = formatterFactory + } + + func createViewModel(from chainAsset: ChainAsset, balanceInPlank: BigUInt?, locale: Locale) -> ChainBalanceViewModel { + let name = chainAsset.chain.name + + let displayInfo = chainAsset.assetDisplayInfo + let tokenFormatter = formatterFactory.createTokenFormatter(for: displayInfo) + + let icon = RemoteImageViewModel(url: chainAsset.asset.icon ?? chainAsset.chain.icon) + + if + let balanceInPlank = balanceInPlank, + let decimalBalance = Decimal.fromSubstrateAmount(balanceInPlank, precision: displayInfo.assetPrecision) { + let balanceString = tokenFormatter.value(for: locale).stringFromDecimal(decimalBalance) + + return ChainBalanceViewModel(name: name, icon: icon, balance: balanceString) + } else { + return ChainBalanceViewModel(name: name, icon: icon, balance: nil) + } + } +} diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift index 5baf9d003b..2cb39b42ac 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListPresenter.swift @@ -27,6 +27,8 @@ final class CrowdloanListPresenter { private let crowdloansCalculator: CrowdloansCalculatorProtocol + private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() + init( interactor: CrowdloanListInteractorInputProtocol, wireframe: CrowdloanListWireframeProtocol, @@ -67,10 +69,9 @@ final class CrowdloanListPresenter { balance = nil } - let viewModel = viewModelFactory.createChainViewModel( - from: chain, - asset: asset, - balance: balance, + let viewModel = chainBalanceFactory.createViewModel( + from: ChainAsset(chain: chain, asset: asset), + balanceInPlank: balance, locale: selectedLocale ) diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift index 51e4e9f7db..dfa60b278d 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift @@ -3,7 +3,7 @@ import SoraFoundation protocol CrowdloansViewProtocol: AlertPresentable, ControllerBackedProtocol, LoadableViewProtocol { var presenter: CrowdloanListPresenterProtocol? { get set } - func didReceive(chainInfo: CrowdloansChainViewModel) + func didReceive(chainInfo: ChainBalanceViewModel) func didReceive(listState: CrowdloanListState) } diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift index 172cf6b76e..73ff6b8032 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift @@ -152,7 +152,7 @@ extension CrowdloanListViewManager: ErrorStateViewDelegate { } extension CrowdloanListViewManager: CrowdloansViewProtocol { - func didReceive(chainInfo: CrowdloansChainViewModel) { + func didReceive(chainInfo: ChainBalanceViewModel) { chainSelectionView.bind(viewModel: chainInfo) } diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModelFactory.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModelFactory.swift index d3bbd2f1f1..de0dce32e3 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModelFactory.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/ViewModel/CrowdloansViewModelFactory.swift @@ -5,13 +5,6 @@ import SubstrateSdk import BigInt protocol CrowdloansViewModelFactoryProtocol { - func createChainViewModel( - from chain: ChainModel, - asset: AssetModel, - balance: BigUInt?, - locale: Locale - ) -> CrowdloansChainViewModel - func createViewModel( from crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, @@ -309,40 +302,6 @@ final class CrowdloansViewModelFactory { } extension CrowdloansViewModelFactory: CrowdloansViewModelFactoryProtocol { - func createChainViewModel( - from chain: ChainModel, - asset: AssetModel, - balance: BigUInt?, - locale: Locale - ) -> CrowdloansChainViewModel { - let displayInfo = asset.displayInfo - - let amountFormatter = amountFormatterFactory.createTokenFormatter( - for: asset.displayInfo - ).value(for: locale) - - let amount: String - - if - let balance = balance, - let decimalAmount = Decimal.fromSubstrateAmount( - balance, - precision: displayInfo.assetPrecision - ) { - amount = amountFormatter.stringFromDecimal(decimalAmount) ?? "" - } else { - amount = "" - } - - let imageViewModel = RemoteImageViewModel(url: asset.icon ?? chain.icon) - - return CrowdloansChainViewModel( - networkName: chain.name, - balance: amount, - imageViewModel: imageViewModel - ) - } - func createErrorViewModel( chainAsset: ChainAssetDisplayInfo?, locale: Locale diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift new file mode 100644 index 0000000000..0efc994ead --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -0,0 +1,13 @@ +import Foundation +import SoraKeystore + +final class GovernanceSharedState { + let settings: GovernanceChainSettings + + init( + chainRegistry: ChainRegistryProtocol = ChainRegistryFacade.sharedRegistry, + internalSettings: SettingsManagerProtocol = SettingsManager.shared + ) { + settings = GovernanceChainSettings(chainRegistry: chainRegistry, settings: internalSettings) + } +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift new file mode 100644 index 0000000000..7ad37f990e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift @@ -0,0 +1,8 @@ +import Foundation + +enum ReferendumsInteractorError: Error { + case settingsLoadFailed + case priceSubscriptionFailed(_ internalError: Error) + case balanceSubscriptionFailed(_ internalError: Error) + case chainSaveFailed(_ internalError: Error) +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 416e574e8b..748a35689e 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -1,7 +1,151 @@ import Foundation +import RobinHood -final class ReferendumsInteractor { +final class ReferendumsInteractor: AnyProviderAutoCleaning { weak var presenter: ReferendumsInteractorOutputProtocol? + + let selectedMetaAccount: MetaAccountModel + let governanceState: GovernanceSharedState + let chainRegistry: ChainRegistryProtocol + let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol + let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol + let currencyManager: CurrencyManagerProtocol + + private var priceProvider: AnySingleValueProvider? + private var assetBalanceProvider: StreamableProvider? + + init( + selectedMetaAccount: MetaAccountModel, + governanceState: GovernanceSharedState, + chainRegistry: ChainRegistryProtocol, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + currencyManager: CurrencyManagerProtocol + ) { + self.selectedMetaAccount = selectedMetaAccount + self.governanceState = governanceState + self.chainRegistry = chainRegistry + self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory + self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory + self.currencyManager = currencyManager + } + + private func clear() { + clear(streamableProvider: &assetBalanceProvider) + clear(singleValueProvider: &priceProvider) + } + + private func continueSetup() { + guard let chain = governanceState.settings.value else { + presenter?.didReceiveError(.settingsLoadFailed) + return + } + + let accountResponse = selectedMetaAccount.fetch(for: chain.accountRequest()) + + setup(with: accountResponse?.accountId, chain: chain) + } + + private func setup(with accountId: AccountId?, chain: ChainModel) { + presenter?.didReceiveSelectedChain(chain) + + if let accountId = accountId { + subscribeToAssetBalance(for: accountId, chain: chain) + } else { + presenter?.didReceiveAssetBalance(nil) + } + + subscribeToAssetPrice(for: chain) + } + + private func subscribeToAssetBalance(for accountId: AccountId, chain: ChainModel) { + guard let asset = chain.utilityAsset() else { + return + } + + assetBalanceProvider = subscribeToAssetBalanceProvider( + for: accountId, + chainId: chain.chainId, + assetId: asset.assetId + ) + } + + private func subscribeToAssetPrice(for chain: ChainModel) { + guard let priceId = chain.utilityAsset()?.priceId else { + return + } + + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } + + private func handleChainChange(for newChain: ChainModel) { + let accountResponse = selectedMetaAccount.fetch(for: newChain.accountRequest()) + + setup(with: accountResponse?.accountId, chain: newChain) + } +} + +extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { + func setup() { + DispatchQueue.global(qos: .userInteractive).async { [weak self] in + self?.governanceState.settings.setup(runningCompletionIn: .main) { result in + switch result { + case .success: + self?.continueSetup() + case .failure: + self?.presenter?.didReceiveError(.settingsLoadFailed) + } + } + } + } + + func saveSelected(chainModel: ChainModel) { + if chainModel.chainId != governanceState.settings.value?.chainId { + clear() + + governanceState.settings.save(value: chainModel, runningCompletionIn: .main) { [weak self] result in + switch result { + case let .success(chain): + self?.handleChainChange(for: chain) + case let .failure(error): + self?.presenter?.didReceiveError(.chainSaveFailed(error)) + } + } + } + } +} + +extension ReferendumsInteractor: WalletLocalSubscriptionHandler, WalletLocalStorageSubscriber { + func handleAssetBalance( + result: Result, + accountId _: AccountId, + chainId _: ChainModel.Id, + assetId _: AssetModel.Id + ) { + switch result { + case let .success(balance): + presenter?.didReceiveAssetBalance(balance) + case let .failure(error): + presenter?.didReceiveError(.balanceSubscriptionFailed(error)) + } + } } -extension ReferendumsInteractor: ReferendumsInteractorInputProtocol {} +extension ReferendumsInteractor: PriceLocalSubscriptionHandler, PriceLocalStorageSubscriber { + func handlePrice(result: Result, priceId _: AssetModel.PriceId) { + switch result { + case let .success(price): + presenter?.didReceivePrice(price) + case let .failure(error): + presenter?.didReceiveError(.priceSubscriptionFailed(error)) + } + } +} + +extension ReferendumsInteractor: SelectedCurrencyDepending { + func applyCurrency() { + if presenter != nil, let chain = governanceState.settings.value { + subscribeToAssetPrice(for: chain) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 94e74ec922..0424a37af2 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -1,4 +1,6 @@ import Foundation +import BigInt +import SoraFoundation final class ReferendumsPresenter { weak var view: ReferendumsViewProtocol? @@ -6,25 +8,103 @@ final class ReferendumsPresenter { let interactor: ReferendumsInteractorInputProtocol let wireframe: ReferendumsWireframeProtocol + private var freeBalance: BigUInt? + private var chain: ChainModel? + private var price: PriceData? + + private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() + init( interactor: ReferendumsInteractorInputProtocol, - wireframe: ReferendumsWireframeProtocol + wireframe: ReferendumsWireframeProtocol, + localizationManager: LocalizationManagerProtocol ) { self.interactor = interactor self.wireframe = wireframe + self.localizationManager = localizationManager + } + + private func provideChainBalance() { + guard let chain = chain, let asset = chain.utilityAsset() else { + return + } + + let viewModel = chainBalanceFactory.createViewModel( + from: ChainAsset(chain: chain, asset: asset), + balanceInPlank: freeBalance, + locale: selectedLocale + ) + + view?.didReceiveChainBalance(viewModel: viewModel) } } extension ReferendumsPresenter: ReferendumsPresenterProtocol {} extension ReferendumsPresenter: VoteChildPresenterProtocol { - func setup() {} + func setup() { + interactor.setup() + } func becomeOnline() {} func putOffline() {} - func selectChain() {} + func selectChain() { + guard let chain = chain, let asset = chain.utilityAsset() else { + return + } + + let chainAssetId = ChainAsset(chain: chain, asset: asset).chainAssetId + + wireframe.selectChain( + from: view, + delegate: self, + selectedChainAssetId: chainAssetId + ) + } +} + +extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { + func didReceiveSelectedChain(_ chain: ChainModel) { + self.chain = chain + + provideChainBalance() + } + + func didReceiveAssetBalance(_ balance: AssetBalance?) { + freeBalance = balance?.freeInPlank ?? 0 + + provideChainBalance() + } + + func didReceivePrice(_ price: PriceData?) { + self.price = price + } + + func didReceiveError(_: ReferendumsInteractorError) {} +} + +extension ReferendumsPresenter: AssetSelectionDelegate { + func assetSelection(view _: AssetSelectionViewProtocol, didCompleteWith chainAsset: ChainAsset) { + if chain?.chainId == chainAsset.chain.chainId { + return + } + + chain = chainAsset.chain + freeBalance = nil + price = nil + + provideChainBalance() + + interactor.saveSelected(chainModel: chainAsset.chain) + } } -extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol {} +extension ReferendumsPresenter: Localizable { + func applyLocalization() { + if let view = view, view.isSetup { + provideChainBalance() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 62aef6c5fb..0d415b1f17 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -1,13 +1,29 @@ import Foundation -protocol ReferendumsViewProtocol: AnyObject { +protocol ReferendumsViewProtocol: ControllerBackedProtocol { var presenter: ReferendumsPresenterProtocol? { get set } + + func didReceiveChainBalance(viewModel: ChainBalanceViewModel) } protocol ReferendumsPresenterProtocol: AnyObject {} -protocol ReferendumsInteractorInputProtocol: AnyObject {} +protocol ReferendumsInteractorInputProtocol: AnyObject { + func setup() + func saveSelected(chainModel: ChainModel) +} -protocol ReferendumsInteractorOutputProtocol: AnyObject {} +protocol ReferendumsInteractorOutputProtocol: AnyObject { + func didReceiveSelectedChain(_ chain: ChainModel) + func didReceiveAssetBalance(_ balance: AssetBalance?) + func didReceivePrice(_ price: PriceData?) + func didReceiveError(_ error: ReferendumsInteractorError) +} -protocol ReferendumsWireframeProtocol: AnyObject {} +protocol ReferendumsWireframeProtocol: AnyObject { + func selectChain( + from view: ControllerBackedProtocol?, + delegate: AssetSelectionDelegate, + selectedChainAssetId: ChainAssetId? + ) +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 572d389d51..3c01c20ed4 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -3,14 +3,16 @@ import UIKit final class ReferendumsViewManager: NSObject { let tableView: UITableView + let chainSelectionView: VoteChainViewProtocol var locale = Locale.current weak var presenter: ReferendumsPresenterProtocol? private weak var parent: ControllerBackedProtocol? - init(tableView: UITableView, parent: ControllerBackedProtocol) { + init(tableView: UITableView, chainSelectionView: VoteChainViewProtocol, parent: ControllerBackedProtocol) { self.tableView = tableView + self.chainSelectionView = chainSelectionView self.parent = parent super.init() @@ -46,7 +48,11 @@ extension ReferendumsViewManager: UITableViewDelegate { } } -extension ReferendumsViewManager: ReferendumsViewProtocol {} +extension ReferendumsViewManager: ReferendumsViewProtocol { + func didReceiveChainBalance(viewModel: ChainBalanceViewModel) { + chainSelectionView.bind(viewModel: viewModel) + } +} extension ReferendumsViewManager: VoteChildViewProtocol { var isSetup: Bool { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index 5b26e53c21..fe82efdb1a 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -1,3 +1,27 @@ import Foundation -final class ReferendumsWireframe: ReferendumsWireframeProtocol {} +final class ReferendumsWireframe: ReferendumsWireframeProtocol { + func selectChain( + from view: ControllerBackedProtocol?, + delegate: AssetSelectionDelegate, + selectedChainAssetId: ChainAssetId? + ) { + let assetFilter: (ChainAsset) -> Bool = { chainAsset in + chainAsset.chain.hasGovernance && chainAsset.asset.isUtility + } + + guard let selectionView = AssetSelectionViewFactory.createView( + delegate: delegate, + selectedChainAssetId: selectedChainAssetId, + assetFilter: assetFilter + ) else { + return + } + + let navigationController = FearlessNavigationController( + rootViewController: selectionView.controller + ) + + view?.controller.present(navigationController, animated: true, completion: nil) + } +} diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift b/novawallet/Modules/Vote/Parent/View/VoteTableHeaderView.swift similarity index 87% rename from novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift rename to novawallet/Modules/Vote/Parent/View/VoteTableHeaderView.swift index 00f47c2610..1b51327fb8 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableHeaderView.swift +++ b/novawallet/Modules/Vote/Parent/View/VoteTableHeaderView.swift @@ -1,7 +1,7 @@ import UIKit import SoraUI -final class CrowdloanTableHeaderView: UIView { +final class VoteTableHeaderView: UIView { let titleLabel: UILabel = { let label = UILabel() label.textColor = R.color.colorWhite() @@ -25,7 +25,7 @@ final class CrowdloanTableHeaderView: UIView { return view }() - private var viewModel: CrowdloansChainViewModel? + private var viewModel: ChainBalanceViewModel? override init(frame: CGRect) { super.init(frame: frame) @@ -77,18 +77,18 @@ final class CrowdloanTableHeaderView: UIView { } } -extension CrowdloanTableHeaderView: VoteChainViewProtocol { - func bind(viewModel: CrowdloansChainViewModel) { - self.viewModel?.imageViewModel?.cancel(on: chainSelectionView.iconView) +extension VoteTableHeaderView: VoteChainViewProtocol { + func bind(viewModel: ChainBalanceViewModel) { + self.viewModel?.icon.cancel(on: chainSelectionView.iconView) chainSelectionView.iconView.image = nil self.viewModel = viewModel - chainSelectionView.title = viewModel.networkName + chainSelectionView.title = viewModel.name chainSelectionView.subtitle = viewModel.balance let iconSize = 2 * chainSelectionView.iconRadius - viewModel.imageViewModel?.loadImage( + viewModel.icon.loadImage( on: chainSelectionView.iconView, targetSize: CGSize(width: iconSize, height: iconSize), animated: true diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index 8df9e6128c..c6e02436ea 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -91,6 +91,20 @@ final class VoteChildPresenterFactory { logger: logger ) } + + private func createGovernanceInteractor( + for state: GovernanceSharedState, + wallet: MetaAccountModel + ) -> ReferendumsInteractor { + ReferendumsInteractor( + selectedMetaAccount: wallet, + governanceState: state, + chainRegistry: chainRegistry, + walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, + priceLocalSubscriptionFactory: priceProviderFactory, + currencyManager: currencyManager + ) + } } extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { @@ -130,12 +144,17 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { func createGovernancePresenter( from view: ReferendumsViewProtocol, - wallet _: MetaAccountModel + wallet: MetaAccountModel ) -> VoteChildPresenterProtocol? { - let interactor = ReferendumsInteractor() + let state = GovernanceSharedState() + let interactor = createGovernanceInteractor(for: state, wallet: wallet) let wireframe = ReferendumsWireframe() - let presenter = ReferendumsPresenter(interactor: interactor, wireframe: wireframe) + let presenter = ReferendumsPresenter( + interactor: interactor, + wireframe: wireframe, + localizationManager: localizationManager + ) presenter.view = view view.presenter = presenter diff --git a/novawallet/Modules/Vote/Parent/VoteProtocols.swift b/novawallet/Modules/Vote/Parent/VoteProtocols.swift index 1a4836824d..94e9b05fb7 100644 --- a/novawallet/Modules/Vote/Parent/VoteProtocols.swift +++ b/novawallet/Modules/Vote/Parent/VoteProtocols.swift @@ -10,7 +10,7 @@ protocol VoteViewProtocol: ControllerBackedProtocol { } protocol VoteChainViewProtocol { - func bind(viewModel: CrowdloansChainViewModel) + func bind(viewModel: ChainBalanceViewModel) } protocol VotePresenterProtocol: AnyObject { diff --git a/novawallet/Modules/Vote/Parent/VoteViewController.swift b/novawallet/Modules/Vote/Parent/VoteViewController.swift index 3d40a0dfc4..2b9723899b 100644 --- a/novawallet/Modules/Vote/Parent/VoteViewController.swift +++ b/novawallet/Modules/Vote/Parent/VoteViewController.swift @@ -101,6 +101,7 @@ final class VoteViewController: UIViewController, ViewHolder { case .governance: let governanceChildView = ReferendumsViewManager( tableView: rootView.tableView, + chainSelectionView: rootView.headerView, parent: self ) diff --git a/novawallet/Modules/Vote/Parent/VoteViewLayout.swift b/novawallet/Modules/Vote/Parent/VoteViewLayout.swift index 8f90b7301c..778cc237cb 100644 --- a/novawallet/Modules/Vote/Parent/VoteViewLayout.swift +++ b/novawallet/Modules/Vote/Parent/VoteViewLayout.swift @@ -4,7 +4,7 @@ import UIKit final class VoteViewLayout: UIView, TableHeaderLayoutUpdatable { private let backgroundView = MultigradientView.background - let headerView = CrowdloanTableHeaderView() + let headerView = VoteTableHeaderView() let tableView: UITableView = { let view = UITableView() From 9424bb6cc4026c0119e9a122337c05f5672d0d2c Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 4 Oct 2022 10:01:09 +0500 Subject: [PATCH 010/229] fix localization --- .../CrowdloanListViewManager.swift | 8 +++++- .../Referendums/ReferendumsViewManager.swift | 8 +++++- .../Parent/View/VoteTableHeaderView.swift | 25 ++++++++++++++++++- .../Vote/Parent/VoteViewController.swift | 4 +-- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift index 73ff6b8032..68f135caf1 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift @@ -6,7 +6,13 @@ final class CrowdloanListViewManager: NSObject { let tableView: UITableView let chainSelectionView: VoteChainViewProtocol - var locale = Locale.current + var locale = Locale.current { + didSet { + if locale != oldValue { + tableView.reloadData() + } + } + } weak var presenter: CrowdloanListPresenterProtocol? private weak var parent: ControllerBackedProtocol? diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 3c01c20ed4..17342cf48a 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -5,7 +5,13 @@ final class ReferendumsViewManager: NSObject { let tableView: UITableView let chainSelectionView: VoteChainViewProtocol - var locale = Locale.current + var locale = Locale.current { + didSet { + if locale != oldValue { + tableView.reloadData() + } + } + } weak var presenter: ReferendumsPresenterProtocol? private weak var parent: ControllerBackedProtocol? diff --git a/novawallet/Modules/Vote/Parent/View/VoteTableHeaderView.swift b/novawallet/Modules/Vote/Parent/View/VoteTableHeaderView.swift index 1b51327fb8..f1090d562c 100644 --- a/novawallet/Modules/Vote/Parent/View/VoteTableHeaderView.swift +++ b/novawallet/Modules/Vote/Parent/View/VoteTableHeaderView.swift @@ -12,7 +12,6 @@ final class VoteTableHeaderView: UIView { let walletSwitch = WalletSwitchControl() let votingTypeSwitch: RoundedSegmentedControl = .create { view in - view.titles = ["Governance", "Crowdloans"] view.backgroundView.fillColor = R.color.colorBlack48()! view.selectionColor = R.color.colorWhite16()! view.titleFont = .regularFootnote @@ -22,16 +21,29 @@ final class VoteTableHeaderView: UIView { let chainSelectionView: DetailsTriangularedView = { let view = UIFactory.default.createChainAssetSelectionView() + view.borderWidth = 0.0 + view.actionImage = R.image.iconMore()?.withRenderingMode(.alwaysTemplate) + view.actionView.tintColor = R.color.colorWhite48() return view }() + var locale = Locale.current { + didSet { + if locale != oldValue { + setupLocalization() + } + } + } + private var viewModel: ChainBalanceViewModel? override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .clear + setupLayout() + setupLocalization() } @available(*, unavailable) @@ -75,6 +87,17 @@ final class VoteTableHeaderView: UIView { make.height.equalTo(52.0) } } + + private func setupLocalization() { + let languages = locale.rLanguages + + titleLabel.text = R.string.localizable.tabbarVoteTitle(preferredLanguages: languages) + + votingTypeSwitch.titles = [ + R.string.localizable.tabbarGovernanceTitle(preferredLanguages: languages), + R.string.localizable.tabbarCrowdloanTitle_v190(preferredLanguages: languages) + ] + } } extension VoteTableHeaderView: VoteChainViewProtocol { diff --git a/novawallet/Modules/Vote/Parent/VoteViewController.swift b/novawallet/Modules/Vote/Parent/VoteViewController.swift index 2b9723899b..c48f0c5028 100644 --- a/novawallet/Modules/Vote/Parent/VoteViewController.swift +++ b/novawallet/Modules/Vote/Parent/VoteViewController.swift @@ -75,9 +75,7 @@ final class VoteViewController: UIViewController, ViewHolder { } private func setupLocalization() { - let languages = selectedLocale.rLanguages - rootView.headerView.titleLabel.text = R.string.localizable.tabbarVoteTitle(preferredLanguages: languages) - + rootView.headerView.locale = selectedLocale childView?.locale = selectedLocale } From fc986f836ba9e46261e8685ca3fef1ef34b18342 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 4 Oct 2022 10:14:12 +0500 Subject: [PATCH 011/229] fix loadable --- .../CrowdloanListViewManager.swift | 21 ++++++++++++------- .../Modules/Vote/Parent/VoteProtocols.swift | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift index 68f135caf1..264207830a 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift @@ -15,11 +15,15 @@ final class CrowdloanListViewManager: NSObject { } weak var presenter: CrowdloanListPresenterProtocol? - private weak var parent: ControllerBackedProtocol? + private weak var parent: (ControllerBackedProtocol & LoadableViewProtocol)? private var state: CrowdloanListState = .loading - init(tableView: UITableView, chainSelectionView: VoteChainViewProtocol, parent: ControllerBackedProtocol) { + init( + tableView: UITableView, + chainSelectionView: VoteChainViewProtocol, + parent: ControllerBackedProtocol & LoadableViewProtocol + ) { self.tableView = tableView self.chainSelectionView = chainSelectionView self.parent = parent @@ -169,19 +173,22 @@ extension CrowdloanListViewManager: CrowdloansViewProtocol { } } -// TODO: Implement for Moonbeam coordinator extension CrowdloanListViewManager: LoadableViewProtocol { var loadableContentView: UIView! { - UIView() + parent?.loadableContentView ?? UIView() } var shouldDisableInteractionWhenLoading: Bool { - false + parent?.shouldDisableInteractionWhenLoading ?? false } - func didStartLoading() {} + func didStartLoading() { + parent?.didStartLoading() + } - func didStopLoading() {} + func didStopLoading() { + parent?.didStopLoading() + } } extension CrowdloanListViewManager: VoteChildViewProtocol { diff --git a/novawallet/Modules/Vote/Parent/VoteProtocols.swift b/novawallet/Modules/Vote/Parent/VoteProtocols.swift index 94e9b05fb7..c7ed65c286 100644 --- a/novawallet/Modules/Vote/Parent/VoteProtocols.swift +++ b/novawallet/Modules/Vote/Parent/VoteProtocols.swift @@ -5,7 +5,7 @@ enum VoteType: UInt8 { case crowdloan } -protocol VoteViewProtocol: ControllerBackedProtocol { +protocol VoteViewProtocol: ControllerBackedProtocol, LoadableViewProtocol { func didSwitchWallet(with viewModel: WalletSwitchViewModel) } From 1e917339d048ed35faf351df1879b297b4b0ddb0 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 4 Oct 2022 11:10:30 +0500 Subject: [PATCH 012/229] fix tests --- novawallet.xcodeproj/project.pbxproj | 14 +- .../Mappers/ChainModelMapperV2V3.swift | 311 + .../SubstrateStorageMigrationTests.swift | 15 +- .../Helper/ChainModelGenerator.swift | 7 +- novawalletTests/Mocks/ModuleMocks.swift | 42749 ++++++++-------- .../CrowdloanList/CrowdloanListTests.swift | 12 +- 6 files changed, 21627 insertions(+), 21481 deletions(-) create mode 100644 novawalletTests/Common/Migration/Mappers/ChainModelMapperV2V3.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 9d3044d2ac..dc0af10ee7 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1555,6 +1555,7 @@ 84B018AE26E03FB500C75E28 /* NominatorStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B018AD26E03FB500C75E28 /* NominatorStateView.swift */; }; 84B018B026E0450F00C75E28 /* ValidatorStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B018AF26E0450F00C75E28 /* ValidatorStateView.swift */; }; 84B28FC428C54441007A1006 /* OnChainTransferAmount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B28FC328C54441007A1006 /* OnChainTransferAmount.swift */; }; + 84B4E12C28EC038C00AC4FA8 /* ChainModelMapperV2V3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B4E12B28EC038C00AC4FA8 /* ChainModelMapperV2V3.swift */; }; 84B5DE53283F7BE500193ED3 /* CollatorsSortType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B5DE52283F7BE500193ED3 /* CollatorsSortType.swift */; }; 84B5DE56283F7C8500193ED3 /* CollatorSelectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B5DE55283F7C8500193ED3 /* CollatorSelectionCell.swift */; }; 84B5DE59283F8B5400193ED3 /* CollatorSelectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B5DE58283F8B5400193ED3 /* CollatorSelectionViewModel.swift */; }; @@ -4343,6 +4344,7 @@ 84B018AD26E03FB500C75E28 /* NominatorStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NominatorStateView.swift; sourceTree = ""; }; 84B018AF26E0450F00C75E28 /* ValidatorStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorStateView.swift; sourceTree = ""; }; 84B28FC328C54441007A1006 /* OnChainTransferAmount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnChainTransferAmount.swift; sourceTree = ""; }; + 84B4E12B28EC038C00AC4FA8 /* ChainModelMapperV2V3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainModelMapperV2V3.swift; sourceTree = ""; }; 84B5DE52283F7BE500193ED3 /* CollatorsSortType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollatorsSortType.swift; sourceTree = ""; }; 84B5DE55283F7C8500193ED3 /* CollatorSelectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollatorSelectionCell.swift; sourceTree = ""; }; 84B5DE58283F8B5400193ED3 /* CollatorSelectionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollatorSelectionViewModel.swift; sourceTree = ""; }; @@ -8365,6 +8367,7 @@ 8489EDD8264DE40800FF997E /* Migration */ = { isa = PBXGroup; children = ( + 84B4E12A28EC036B00AC4FA8 /* Mappers */, 849ECD3426DE70B900F542A3 /* SingleToMultiassetUserMigrationTests.swift */, 8890E51528DDC98C001D3994 /* SubstrateStorageMigrationTests.swift */, ); @@ -9826,6 +9829,14 @@ path = SiMappers; sourceTree = ""; }; + 84B4E12A28EC036B00AC4FA8 /* Mappers */ = { + isa = PBXGroup; + children = ( + 84B4E12B28EC038C00AC4FA8 /* ChainModelMapperV2V3.swift */, + ); + path = Mappers; + sourceTree = ""; + }; 84B5DE54283F7C6000193ED3 /* View */ = { isa = PBXGroup; children = ( @@ -13529,7 +13540,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "#! /bin/sh\n# Define output file. Change \"$PROJECT_DIR/${PROJECT_NAME}Tests\" to your test's root source folder, if it's not the default name.\nOUTPUT_FILE=\"${PROJECT_NAME}Tests/Mocks/ModuleMocks.swift\"\necho \"Generated Mocks File = $OUTPUT_FILE\"\n\n# Define input directory. Change \"${PROJECT_DIR}/${PROJECT_NAME}\" to your project's root source folder, if it's not the default name.\nINPUT_DIR=\"${PROJECT_NAME}\"\necho \"Mocks Input Directory = $INPUT_DIR\"\n\n# Generate mock files, include as many input files as you'd like to create mocks for.\n\"Pods/Cuckoo/run\" generate --no-header --testable \"${PROJECT_NAME}\" \\\n--exclude \"RootPresenterFactoryProtocol, UsernameSetupViewFactoryProtocol, OnboardingMainViewFactoryProtocol, AccountCreateViewFactoryProtocol, AccountImportViewFactoryProtocol, AccountConfirmViewFactoryProtocol, PinViewFactoryProtocol, ProfileViewFactoryProtocol, AccountManagementViewFactoryProtocol, AccountInfoViewFactoryProtocol, NetworkManagementViewFactoryProtocol, NetworkInfoViewFactoryProtocol, AddConnectionViewFactoryProtocol, AccountExportPasswordViewFactoryProtocol, ExportRestoreJsonViewFactoryProtocol, ExportMnemonicViewFactoryProtocol, StakingMainViewFactoryProtocol, SelectValidatorsStartViewFactoryProtocol, SelectValidatorsConfirmViewFactoryProtocol, RecommendedValidatorListViewFactoryProtocol, SelectedValidatorListViewFactoryProtocol, CustomValidatorListViewFactoryProtocol, ValidatorInfoViewFactoryProtocol, WalletHistoryFilterViewFactoryProtocol, StakingPayoutConfirmationViewFactoryProtocol, StakingRewardDetailsViewFactoryProtocol, StakingRewardPayoutsViewFactoryProtocol, StakingPayoutConfirmViewModelFactoryProtocol, YourValidatorListViewFactoryProtocol, StakingUnbondSetupViewFactoryProtocol, StakingUnbondConfirmViewFactoryProtocol, StakingRedeemViewFactoryProtocol, StakingBondMoreViewFactoryProtocol, StakingRebondSetupViewFactoryProtocol, ValidatorListFilterViewFactoryProtocol, ValidatorSearchViewFactoryProtocol\" \\\n--output \"${OUTPUT_FILE}\" \\\n\"$INPUT_DIR/../Pods/SoraFoundation/SoraFoundation/Classes/Localization/Localizable.swift\" \\\n\"$INPUT_DIR/Common/Protocols/LoadableViewProtocol.swift\" \\\n\"$INPUT_DIR/Common/Protocols/ControllerBackedProtocol.swift\" \\\n\"$INPUT_DIR/Common/Protocols/WebPresentable.swift\" \\\n\"$INPUT_DIR/Common/Protocols/AlertPresentable.swift\" \\\n\"$INPUT_DIR/Common/Protocols/ModalAlertPresenting.swift\" \\\n\"$INPUT_DIR/Common/Protocols/SharingPresentable.swift\" \\\n\"$INPUT_DIR/Common/Protocols/AccountSelectionPresentable.swift\" \\\n\"$INPUT_DIR/Modules/Root/RootProtocol.swift\" \\\n\"$INPUT_DIR/Modules/UsernameSetup/UsernameSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/OnbordingMain/OnboardingMainProtocol.swift\" \\\n\"$INPUT_DIR/Modules/AccountCreate/AccountCreateProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AccountImport/AccountImportProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AccountConfirm/AccountConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Pincode/PinSetup/PinSetupProtocol.swift\" \\\n\"$INPUT_DIR/Modules/Settings/SettingsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AccountManagement/AccountManagementProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AccountInfo/AccountInfoProtocols.swift\" \\\n\"$INPUT_DIR/Modules/NetworkManagement/NetworkManagementProtocols.swift\" \\\n\"$INPUT_DIR/Modules/NetworkInfo/NetworkInfoProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AddConnection/AddConnectionProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Export/AccountExportPassword/AccountExportPasswordProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Export/ExportGenericView/ExportGenericProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Export/ExportMnemonic/ExportMnemonicProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Export/ExportRestoreJson/ExportRestoreJsonProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Wallet/HistoryFilter/WalletHistoryFilterProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/Operations/ValidatorOperationFactory/ValidatorOperationFactoryProtocol.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingMain/StakingMainProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/Operations/NetworkStakingInfoOperationFactory.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingPayoutConfirmation/StakingPayoutConfirmationProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRewardDetails/StakingRewardDetailsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRewardPayouts/StakingRewardPayoutsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingBalance/StakingBalanceProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingUnbondSetup/StakingUnbondSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingUnbondConfirm/StakingUnbondConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRedeem/StakingRedeemProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingBondMore/StakingBondMoreProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingBondMoreConfirmation/StakingBondMoreConfirmationProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRebondSetup/StakingRebondSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRebondConfirmation/StakingRebondConfirmationProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/ControllerAccount/ControllerAccountProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRewardDestinationSetup/StakingRewardDestSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRewardDestConfirm/StakingRewardDestConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/SelectValidatorsStart/SelectValidatorsStartProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/YourValidatorList/YourValidatorListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/ValidatorListFilter/ValidatorListFilterProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/ValidatorSearch/ValidatorSearchProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/SelectValidatorsConfirm/SelectValidatorsConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/RecommendedValidatorList/RecommendedValidatorListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/SelectedValidatorList/SelectedValidatorListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/CustomValidatorList/CustomValidatorListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/ValidatorInfo/ValidatorInfoProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Crowdloan/CrowdloanContribution/CrowdloanContributionProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Crowdloan/CustomCrowdloan/CustomCrowdloanDelegate.swift\" \\\n\"$INPUT_DIR/Modules/Crowdloan/ReferralCrowdloan/ReferralCrowdloanProtocols.swift\" \\\n\"$INPUT_DIR/Common/ViewController/SelectionListViewController/SelectionListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AssetSelection/AssetSelectionProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/Analytics/AnalyticsRewardDetails/AnalyticsRewardDetailsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AdvancedWallet/AdvancedWalletProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppAuthConfirm/DAppAuthConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppList/DAppListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppBrowser/DAppBrowserProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppOperationConfirm/DAppOperationConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppSearch/DAppSearchProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AssetsManage/AssetsManageProtocols.swift\" \\\n\"$INPUT_DIR/Modules/OperationDetails/OperationDetailsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsProtocols.swift\" \\\n"; + shellScript = "#! /bin/sh\n# Define output file. Change \"$PROJECT_DIR/${PROJECT_NAME}Tests\" to your test's root source folder, if it's not the default name.\nOUTPUT_FILE=\"${PROJECT_NAME}Tests/Mocks/ModuleMocks.swift\"\necho \"Generated Mocks File = $OUTPUT_FILE\"\n\n# Define input directory. Change \"${PROJECT_DIR}/${PROJECT_NAME}\" to your project's root source folder, if it's not the default name.\nINPUT_DIR=\"${PROJECT_NAME}\"\necho \"Mocks Input Directory = $INPUT_DIR\"\n\n# Generate mock files, include as many input files as you'd like to create mocks for.\n\"Pods/Cuckoo/run\" generate --no-header --testable \"${PROJECT_NAME}\" \\\n--exclude \"RootPresenterFactoryProtocol, UsernameSetupViewFactoryProtocol, OnboardingMainViewFactoryProtocol, AccountCreateViewFactoryProtocol, AccountImportViewFactoryProtocol, AccountConfirmViewFactoryProtocol, PinViewFactoryProtocol, ProfileViewFactoryProtocol, AccountManagementViewFactoryProtocol, AccountInfoViewFactoryProtocol, NetworkManagementViewFactoryProtocol, NetworkInfoViewFactoryProtocol, AddConnectionViewFactoryProtocol, AccountExportPasswordViewFactoryProtocol, ExportRestoreJsonViewFactoryProtocol, ExportMnemonicViewFactoryProtocol, StakingMainViewFactoryProtocol, SelectValidatorsStartViewFactoryProtocol, SelectValidatorsConfirmViewFactoryProtocol, RecommendedValidatorListViewFactoryProtocol, SelectedValidatorListViewFactoryProtocol, CustomValidatorListViewFactoryProtocol, ValidatorInfoViewFactoryProtocol, WalletHistoryFilterViewFactoryProtocol, StakingPayoutConfirmationViewFactoryProtocol, StakingRewardDetailsViewFactoryProtocol, StakingRewardPayoutsViewFactoryProtocol, StakingPayoutConfirmViewModelFactoryProtocol, YourValidatorListViewFactoryProtocol, StakingUnbondSetupViewFactoryProtocol, StakingUnbondConfirmViewFactoryProtocol, StakingRedeemViewFactoryProtocol, StakingBondMoreViewFactoryProtocol, StakingRebondSetupViewFactoryProtocol, ValidatorListFilterViewFactoryProtocol, ValidatorSearchViewFactoryProtocol\" \\\n--output \"${OUTPUT_FILE}\" \\\n\"$INPUT_DIR/../Pods/SoraFoundation/SoraFoundation/Classes/Localization/Localizable.swift\" \\\n\"$INPUT_DIR/Common/Protocols/LoadableViewProtocol.swift\" \\\n\"$INPUT_DIR/Common/Protocols/ControllerBackedProtocol.swift\" \\\n\"$INPUT_DIR/Common/Protocols/WebPresentable.swift\" \\\n\"$INPUT_DIR/Common/Protocols/AlertPresentable.swift\" \\\n\"$INPUT_DIR/Common/Protocols/ModalAlertPresenting.swift\" \\\n\"$INPUT_DIR/Common/Protocols/SharingPresentable.swift\" \\\n\"$INPUT_DIR/Common/Protocols/AccountSelectionPresentable.swift\" \\\n\"$INPUT_DIR/Modules/Root/RootProtocol.swift\" \\\n\"$INPUT_DIR/Modules/UsernameSetup/UsernameSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/OnbordingMain/OnboardingMainProtocol.swift\" \\\n\"$INPUT_DIR/Modules/AccountCreate/AccountCreateProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AccountImport/AccountImportProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AccountConfirm/AccountConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Pincode/PinSetup/PinSetupProtocol.swift\" \\\n\"$INPUT_DIR/Modules/Settings/SettingsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AccountManagement/AccountManagementProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AccountInfo/AccountInfoProtocols.swift\" \\\n\"$INPUT_DIR/Modules/NetworkManagement/NetworkManagementProtocols.swift\" \\\n\"$INPUT_DIR/Modules/NetworkInfo/NetworkInfoProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AddConnection/AddConnectionProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Export/AccountExportPassword/AccountExportPasswordProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Export/ExportGenericView/ExportGenericProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Export/ExportMnemonic/ExportMnemonicProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Export/ExportRestoreJson/ExportRestoreJsonProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Wallet/HistoryFilter/WalletHistoryFilterProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/Operations/ValidatorOperationFactory/ValidatorOperationFactoryProtocol.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingMain/StakingMainProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/Operations/NetworkStakingInfoOperationFactory.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingPayoutConfirmation/StakingPayoutConfirmationProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRewardDetails/StakingRewardDetailsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRewardPayouts/StakingRewardPayoutsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingBalance/StakingBalanceProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingUnbondSetup/StakingUnbondSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingUnbondConfirm/StakingUnbondConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRedeem/StakingRedeemProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingBondMore/StakingBondMoreProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingBondMoreConfirmation/StakingBondMoreConfirmationProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRebondSetup/StakingRebondSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRebondConfirmation/StakingRebondConfirmationProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/ControllerAccount/ControllerAccountProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRewardDestinationSetup/StakingRewardDestSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/StakingRewardDestConfirm/StakingRewardDestConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/SelectValidatorsStart/SelectValidatorsStartProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/YourValidatorList/YourValidatorListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/ValidatorListFilter/ValidatorListFilterProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/ValidatorSearch/ValidatorSearchProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/SelectValidatorsConfirm/SelectValidatorsConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/RecommendedValidatorList/RecommendedValidatorListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/SelectedValidatorList/SelectedValidatorListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/CustomValidatorList/CustomValidatorListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/SelectValidatorsFlow/ValidatorInfo/ValidatorInfoProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Vote/Crowdloan/CrowdloanContribution/CrowdloanContributionProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Vote/Crowdloan/CrowdloanContributionSetup/CrowdloanContributionSetupProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Vote/Crowdloan/CrowdloanContributionConfirm/CrowdloanContributionConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Vote/Crowdloan/CustomCrowdloan/CustomCrowdloanDelegate.swift\" \\\n\"$INPUT_DIR/Modules/Vote/Crowdloan/ReferralCrowdloan/ReferralCrowdloanProtocols.swift\" \\\n\"$INPUT_DIR/Common/ViewController/SelectionListViewController/SelectionListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AssetSelection/AssetSelectionProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Staking/Analytics/AnalyticsRewardDetails/AnalyticsRewardDetailsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AdvancedWallet/AdvancedWalletProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppAuthConfirm/DAppAuthConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppList/DAppListProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppBrowser/DAppBrowserProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppOperationConfirm/DAppOperationConfirmProtocols.swift\" \\\n\"$INPUT_DIR/Modules/DApp/DAppSearch/DAppSearchProtocols.swift\" \\\n\"$INPUT_DIR/Modules/AssetsManage/AssetsManageProtocols.swift\" \\\n\"$INPUT_DIR/Modules/OperationDetails/OperationDetailsProtocols.swift\" \\\n\"$INPUT_DIR/Modules/Vote/Crowdloan/CrowdloanYourContributions/CrowdloanYourContributionsProtocols.swift\" \\\n"; }; 842D1E8924D207D900C30A7A /* Common Mock */ = { isa = PBXShellScriptBuildPhase; @@ -16245,6 +16256,7 @@ 843EC7A82701F63600C7DC7E /* PriceProviderFactoryStub.swift in Sources */, 8890E51628DDC98C001D3994 /* SubstrateStorageMigrationTests.swift in Sources */, 84B7C70E289BFA79001A3566 /* SettingsTests.swift in Sources */, + 84B4E12C28EC038C00AC4FA8 /* ChainModelMapperV2V3.swift in Sources */, 84563D0924F46B7F0055591D /* ManagedAccountItemMapperTests.swift in Sources */, 845B822726EFFE0200D25C72 /* MetaAccountMapperTests.swift in Sources */, 84B7C738289BFA79001A3566 /* StakingRebondSetupTests.swift in Sources */, diff --git a/novawalletTests/Common/Migration/Mappers/ChainModelMapperV2V3.swift b/novawalletTests/Common/Migration/Mappers/ChainModelMapperV2V3.swift new file mode 100644 index 0000000000..084a371daa --- /dev/null +++ b/novawalletTests/Common/Migration/Mappers/ChainModelMapperV2V3.swift @@ -0,0 +1,311 @@ +import Foundation +@testable import novawallet +import CoreData +import RobinHood +import SubstrateSdk + +final class ChainModelMapperV2V3 { + var entityIdentifierFieldName: String { #keyPath(CDChain.chainId) } + + typealias DataProviderModel = ChainModel + typealias CoreDataEntity = CDChain + + private lazy var jsonEncoder = JSONEncoder() + private lazy var jsonDecoder = JSONDecoder() + + private func createAsset(from entity: CDAsset) throws -> AssetModel { + let typeExtras: JSON? + + if let data = entity.typeExtras { + typeExtras = try jsonDecoder.decode(JSON.self, from: data) + } else { + typeExtras = nil + } + + let buyProviders: JSON? + + if let data = entity.buyProviders { + buyProviders = try jsonDecoder.decode(JSON.self, from: data) + } else { + buyProviders = nil + } + + return AssetModel( + assetId: UInt32(bitPattern: entity.assetId), + icon: entity.icon, + name: entity.name, + symbol: entity.symbol!, + precision: UInt16(bitPattern: entity.precision), + priceId: entity.priceId, + staking: entity.staking, + type: entity.type, + typeExtras: typeExtras, + buyProviders: buyProviders + ) + } + + private func createChainNode(from entity: CDChainNode) -> ChainNodeModel { + let apiKey: ChainNodeModel.ApiKey? + + if let queryName = entity.apiQueryName, let keyName = entity.apiKeyName { + apiKey = ChainNodeModel.ApiKey(queryName: queryName, keyName: keyName) + } else { + apiKey = nil + } + + return ChainNodeModel( + url: entity.url!, + name: entity.name!, + apikey: apiKey, + order: entity.order + ) + } + + private func updateEntityAssets( + for entity: CDChain, + from model: ChainModel, + context: NSManagedObjectContext + ) throws { + let assetEntities: [CDAsset] = try model.assets.map { asset in + let assetEntity: CDAsset + let assetEntityId = Int32(bitPattern: asset.assetId) + + let maybeExistingEntity = entity.assets? + .first { ($0 as? CDAsset)?.assetId == assetEntityId } as? CDAsset + + if let existingEntity = maybeExistingEntity { + assetEntity = existingEntity + } else { + assetEntity = CDAsset(context: context) + } + + assetEntity.assetId = assetEntityId + assetEntity.name = asset.name + assetEntity.precision = Int16(bitPattern: asset.precision) + assetEntity.icon = asset.icon + assetEntity.symbol = asset.symbol + assetEntity.priceId = asset.priceId + assetEntity.staking = asset.staking + assetEntity.type = asset.type + + if let json = asset.typeExtras { + assetEntity.typeExtras = try jsonEncoder.encode(json) + } else { + assetEntity.typeExtras = nil + } + + if let json = asset.buyProviders { + assetEntity.buyProviders = try jsonEncoder.encode(json) + } else { + assetEntity.buyProviders = nil + } + + return assetEntity + } + + let existingAssetIds = Set(model.assets.map(\.assetId)) + + if let oldAssets = entity.assets as? Set { + for oldAsset in oldAssets { + if !existingAssetIds.contains(UInt32(bitPattern: oldAsset.assetId)) { + context.delete(oldAsset) + } + } + } + + entity.assets = Set(assetEntities) as NSSet + } + + private func updateEntityNodes( + for entity: CDChain, + from model: ChainModel, + context: NSManagedObjectContext + ) { + let nodeEntities: [CDChainNode] = model.nodes.map { node in + let nodeEntity: CDChainNode + + let maybeExistingEntity = entity.nodes? + .first { ($0 as? CDChainNode)?.url == node.url } as? CDChainNode + + if let existingEntity = maybeExistingEntity { + nodeEntity = existingEntity + } else { + nodeEntity = CDChainNode(context: context) + } + + nodeEntity.url = node.url + nodeEntity.name = node.name + nodeEntity.apiQueryName = node.apikey?.queryName + nodeEntity.apiKeyName = node.apikey?.keyName + nodeEntity.order = node.order + + return nodeEntity + } + + let existingNodeIds = Set(model.nodes.map(\.url)) + + if let oldNodes = entity.nodes as? Set { + for oldNode in oldNodes { + if !existingNodeIds.contains(oldNode.url!) { + context.delete(oldNode) + } + } + } + + entity.nodes = Set(nodeEntities) as NSSet + } + + private func createExplorers(from chain: CDChain) -> [ChainModel.Explorer]? { + guard let data = chain.explorers else { + return nil + } + + return try? JSONDecoder().decode([ChainModel.Explorer].self, from: data) + } + + private func updateExplorers(for entity: CDChain, from explorers: [ChainModel.Explorer]?) { + if let explorers = explorers { + entity.explorers = try? JSONEncoder().encode(explorers) + } else { + entity.explorers = nil + } + } + + private func createExternalApi(from entity: CDChain) -> ChainModel.ExternalApiSet? { + let staking: ChainModel.ExternalApi? + + if let type = entity.stakingApiType, let url = entity.stakingApiUrl { + staking = ChainModel.ExternalApi(type: type, url: url) + } else { + staking = nil + } + + let history: ChainModel.ExternalApi? + + if let type = entity.historyApiType, let url = entity.historyApiUrl { + history = ChainModel.ExternalApi(type: type, url: url) + } else { + history = nil + } + + let crowdloans: ChainModel.ExternalApi? + + if let type = entity.crowdloansApiType, let url = entity.crowdloansApiUrl { + crowdloans = ChainModel.ExternalApi(type: type, url: url) + } else { + crowdloans = nil + } + + if staking != nil || history != nil || crowdloans != nil { + return ChainModel.ExternalApiSet(staking: staking, history: history, crowdloans: crowdloans) + } else { + return nil + } + } + + private func updateExternalApis(in entity: CDChain, from apis: ChainModel.ExternalApiSet?) { + entity.stakingApiType = apis?.staking?.type + entity.stakingApiUrl = apis?.staking?.url + + entity.historyApiType = apis?.history?.type + entity.historyApiUrl = apis?.history?.url + + entity.crowdloansApiType = apis?.crowdloans?.type + entity.crowdloansApiUrl = apis?.crowdloans?.url + } +} + +extension ChainModelMapperV2V3: CoreDataMapperProtocol { + func transform(entity: CDChain) throws -> ChainModel { + let assets: [AssetModel] = try entity.assets?.compactMap { anyAsset in + guard let asset = anyAsset as? CDAsset else { + return nil + } + + return try createAsset(from: asset) + } ?? [] + + let nodes: [ChainNodeModel] = entity.nodes?.compactMap { anyNode in + guard let node = anyNode as? CDChainNode else { + return nil + } + + return createChainNode(from: node) + } ?? [] + + let types: ChainModel.TypesSettings? + + if let url = entity.types, let overridesCommon = entity.typesOverrideCommon { + types = .init(url: url, overridesCommon: overridesCommon.boolValue) + } else { + types = nil + } + + var options: [ChainOptions] = [] + + if entity.isEthereumBased { + options.append(.ethereumBased) + } + + if entity.isTestnet { + options.append(.testnet) + } + + if entity.hasCrowdloans { + options.append(.crowdloans) + } + + let externalApiSet = createExternalApi(from: entity) + let explorers = createExplorers(from: entity) + + let additional: JSON? = try entity.additional.map { + try jsonDecoder.decode(JSON.self, from: $0) + } + + return ChainModel( + chainId: entity.chainId!, + parentId: entity.parentId, + name: entity.name!, + assets: Set(assets), + nodes: Set(nodes), + addressPrefix: UInt16(bitPattern: entity.addressPrefix), + types: types, + icon: entity.icon!, + options: options.isEmpty ? nil : options, + externalApi: externalApiSet, + explorers: explorers, + order: entity.order, + additional: additional + ) + } + + func populate( + entity: CDChain, + from model: ChainModel, + using context: NSManagedObjectContext + ) throws { + entity.chainId = model.chainId + entity.parentId = model.parentId + entity.name = model.name + entity.types = model.types?.url + entity.typesOverrideCommon = model.types.map { NSNumber(value: $0.overridesCommon) } + + entity.addressPrefix = Int16(bitPattern: model.addressPrefix) + entity.icon = model.icon + entity.isEthereumBased = model.isEthereumBased + entity.isTestnet = model.isTestnet + entity.hasCrowdloans = model.hasCrowdloans + entity.order = model.order + entity.additional = try model.additional.map { + try jsonEncoder.encode($0) + } + + try updateEntityAssets(for: entity, from: model, context: context) + + updateEntityNodes(for: entity, from: model, context: context) + + updateExternalApis(in: entity, from: model.externalApi) + + updateExplorers(for: entity, from: model.explorers) + } +} diff --git a/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift b/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift index a8edf0bdcb..ce602d3d09 100644 --- a/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift +++ b/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift @@ -15,6 +15,7 @@ final class SubstrateStorageMigrationTests: XCTestCase { let databaseName = SubstrateStorageParams.databaseName let modelDirectory = SubstrateStorageParams.modelDirectory var storeURL: URL { databaseDirectoryURL.appendingPathComponent(databaseName) } + let oldMapper = ChainModelMapperV2V3() let mapper = ChainModelMapper() override func setUpWithError() throws { @@ -30,14 +31,14 @@ final class SubstrateStorageMigrationTests: XCTestCase { try removeDirectory(at: databaseDirectoryURL) } - func testMigrationVersion1ToVersion2() { + func testMigrationVersion2ToVersion3() { let timeout: TimeInterval = 5 let generatedChains = generateChainsWithTimeout(timeout) XCTAssertGreaterThan(generatedChains.count, 0) let migrator = SubstrateStorageMigrator(storeURL: storeURL, modelDirectory: modelDirectory, - model: .version2, + model: .version3, fileManager: FileManager.default) XCTAssertTrue(migrator.requiresMigration(), "Migration is not required") @@ -94,7 +95,7 @@ final class SubstrateStorageMigrationTests: XCTestCase { private func generateChains(completion: @escaping (Result<[ChainModel], Error>) -> Void) { let chains = ChainModelGenerator.generate(count: 5) - let dbService = createCoreDataService(for: .version1) + let dbService = createCoreDataService(for: .version2) dbService.performAsync { [unowned self] (context, error) in if let error = error { @@ -115,9 +116,9 @@ final class SubstrateStorageMigrationTests: XCTestCase { throw TestError.unexpectedEntity } - try mapper.populate(entity: newChain, - from: $0, - using: context) + try oldMapper.populate(entity: newChain, + from: $0, + using: context) } @@ -131,7 +132,7 @@ final class SubstrateStorageMigrationTests: XCTestCase { } private func fetchChains(completion: @escaping (Result<[ChainModel], Error>) -> Void) { - let dbService = createCoreDataService(for: .version2) + let dbService = createCoreDataService(for: .version3) dbService.performAsync { [unowned self] (context, error) in if let error = error { diff --git a/novawalletTests/Helper/ChainModelGenerator.swift b/novawalletTests/Helper/ChainModelGenerator.swift index b90335453a..74838ecbe6 100644 --- a/novawalletTests/Helper/ChainModelGenerator.swift +++ b/novawalletTests/Helper/ChainModelGenerator.swift @@ -7,7 +7,8 @@ enum ChainModelGenerator { count: Int, withTypes: Bool = true, hasStaking: Bool = false, - hasCrowdloans: Bool = false + hasCrowdloans: Bool = false, + hasGovernance: Bool = false ) -> [ChainModel] { (0.. Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt, CrowdloanBonusServiceProtocol?)> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorInputProtocol.self, method: "estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") + } + + + func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthViewModel)> where M1.MatchedType == DAppAuthViewModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmViewProtocol.self, method: "didReceive(viewModel: DAppAuthViewModel)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppAuthConfirmViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -8008,38 +8023,54 @@ import Foundation } - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + @discardableResult - func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.__DoNotUse<(BigUInt, CrowdloanBonusServiceProtocol?), Void> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] - return cuckoo_manager.verify("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(DAppAuthViewModel), Void> where M1.MatchedType == DAppAuthViewModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceive(viewModel: DAppAuthViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionInteractorInputProtocolStub: CrowdloanContributionInteractorInputProtocol { - - + class DAppAuthConfirmViewProtocolStub: DAppAuthConfirmViewProtocol { + - + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + + + + - func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { + func didReceive(viewModel: DAppAuthViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -8047,19 +8078,19 @@ import Foundation - class MockCrowdloanContributionInteractorOutputProtocol: CrowdloanContributionInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockDAppAuthConfirmPresenterProtocol: DAppAuthConfirmPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionInteractorOutputProtocol + typealias MocksType = DAppAuthConfirmPresenterProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionInteractorOutputProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_DAppAuthConfirmPresenterProtocol + typealias Verification = __VerificationProxy_DAppAuthConfirmPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionInteractorOutputProtocol? + private var __defaultImplStub: DAppAuthConfirmPresenterProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: DAppAuthConfirmPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -8072,171 +8103,178 @@ import Foundation - func didReceiveCrowdloan(result: Result) { + func setup() { - return cuckoo_manager.call("didReceiveCrowdloan(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveCrowdloan(result: result)) + defaultCall: __defaultImplStub!.setup()) } - func didReceiveDisplayInfo(result: Result) { + func allow() { - return cuckoo_manager.call("didReceiveDisplayInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("allow()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveDisplayInfo(result: result)) + defaultCall: __defaultImplStub!.allow()) } - func didReceiveAccountInfo(result: Result) { + func deny() { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("deny()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.deny()) } + + struct __StubbingProxy_DAppAuthConfirmPresenterProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func allow() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmPresenterProtocol.self, method: "allow()", parameterMatchers: matchers)) + } + + func deny() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmPresenterProtocol.self, method: "deny()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_DAppAuthConfirmPresenterProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func allow() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("allow()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func deny() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("deny()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class DAppAuthConfirmPresenterProtocolStub: DAppAuthConfirmPresenterProtocol { + - func didReceiveBlockNumber(result: Result) { - - return cuckoo_manager.call("didReceiveBlockNumber(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBlockNumber(result: result)) - - } + - func didReceiveBlockDuration(result: Result) { - - return cuckoo_manager.call("didReceiveBlockDuration(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBlockDuration(result: result)) - + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveLeasingPeriod(result: Result) { - - return cuckoo_manager.call("didReceiveLeasingPeriod(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(result: result)) - + func allow() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveLeasingOffset(result: Result) { - - return cuckoo_manager.call("didReceiveLeasingOffset(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveLeasingOffset(result: result)) - + func deny() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockDAppAuthConfirmWireframeProtocol: DAppAuthConfirmWireframeProtocol, Cuckoo.ProtocolMock { + typealias MocksType = DAppAuthConfirmWireframeProtocol - func didReceiveMinimumBalance(result: Result) { - - return cuckoo_manager.call("didReceiveMinimumBalance(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveMinimumBalance(result: result)) - - } - - + typealias Stubbing = __StubbingProxy_DAppAuthConfirmWireframeProtocol + typealias Verification = __VerificationProxy_DAppAuthConfirmWireframeProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func didReceiveMinimumContribution(result: Result) { - - return cuckoo_manager.call("didReceiveMinimumContribution(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveMinimumContribution(result: result)) - + private var __defaultImplStub: DAppAuthConfirmWireframeProtocol? + + func enableDefaultImplementation(_ stub: DAppAuthConfirmWireframeProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func didReceivePriceData(result: Result) { - - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) - - } + - func didReceiveFee(result: Result) { + func close(from view: DAppAuthConfirmViewProtocol?) { - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("close(from: DAppAuthConfirmViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + defaultCall: __defaultImplStub!.close(from: view)) } - struct __StubbingProxy_CrowdloanContributionInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppAuthConfirmWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -8244,64 +8282,14 @@ import Foundation } - func didReceiveCrowdloan(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveCrowdloan(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveDisplayInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveDisplayInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveBlockNumber(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveBlockNumber(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveBlockDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveBlockDuration(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveLeasingPeriod(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveLeasingOffset(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveMinimumBalance(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveMinimumBalance(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveMinimumContribution(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveMinimumContribution(result: Result)", parameterMatchers: matchers)) - } - - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + func close(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthConfirmViewProtocol?)> where M1.OptionalMatchedType == DAppAuthConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmWireframeProtocol.self, method: "close(from: DAppAuthConfirmViewProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppAuthConfirmWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -8316,75 +8304,15 @@ import Foundation @discardableResult - func didReceiveCrowdloan(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveCrowdloan(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveDisplayInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveDisplayInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBlockNumber(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBlockNumber(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBlockDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBlockDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveLeasingPeriod(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingPeriod(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveLeasingOffset(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingOffset(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveMinimumBalance(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMinimumBalance(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveMinimumContribution(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMinimumContribution(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func close(from view: M1) -> Cuckoo.__DoNotUse<(DAppAuthConfirmViewProtocol?), Void> where M1.OptionalMatchedType == DAppAuthConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(from: DAppAuthConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionInteractorOutputProtocolStub: CrowdloanContributionInteractorOutputProtocol { + class DAppAuthConfirmWireframeProtocolStub: DAppAuthConfirmWireframeProtocol { @@ -8392,67 +8320,100 @@ import Foundation - func didReceiveCrowdloan(result: Result) { + func close(from view: DAppAuthConfirmViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockDAppAuthDelegate: DAppAuthDelegate, Cuckoo.ProtocolMock { + typealias MocksType = DAppAuthDelegate - func didReceiveDisplayInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - + typealias Stubbing = __StubbingProxy_DAppAuthDelegate + typealias Verification = __VerificationProxy_DAppAuthDelegate + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func didReceiveAccountInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + private var __defaultImplStub: DAppAuthDelegate? + + func enableDefaultImplementation(_ stub: DAppAuthDelegate) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func didReceiveBlockNumber(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceiveBlockDuration(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveLeasingPeriod(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveLeasingOffset(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveMinimumBalance(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveMinimumContribution(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func didReceiveAuthResponse(_ response: DAppAuthResponse, for request: DAppAuthRequest) { + + return cuckoo_manager.call("didReceiveAuthResponse(_: DAppAuthResponse, for: DAppAuthRequest)", + parameters: (response, request), + escapingParameters: (response, request), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveAuthResponse(response, for: request)) + } + + struct __StubbingProxy_DAppAuthDelegate: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func didReceiveAuthResponse(_ response: M1, for request: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthResponse, DAppAuthRequest)> where M1.MatchedType == DAppAuthResponse, M2.MatchedType == DAppAuthRequest { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthResponse, DAppAuthRequest)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: request) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthDelegate.self, method: "didReceiveAuthResponse(_: DAppAuthResponse, for: DAppAuthRequest)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_DAppAuthDelegate: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func didReceiveAuthResponse(_ response: M1, for request: M2) -> Cuckoo.__DoNotUse<(DAppAuthResponse, DAppAuthRequest), Void> where M1.MatchedType == DAppAuthResponse, M2.MatchedType == DAppAuthRequest { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthResponse, DAppAuthRequest)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: request) { $0.1 }] + return cuckoo_manager.verify("didReceiveAuthResponse(_: DAppAuthResponse, for: DAppAuthRequest)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class DAppAuthDelegateStub: DAppAuthDelegate { + - func didReceivePriceData(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceiveFee(result: Result) { + func didReceiveAuthResponse(_ response: DAppAuthResponse, for request: DAppAuthRequest) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -8462,23 +8423,23 @@ import Foundation import Cuckoo @testable import novawallet -import BigInt -import SoraFoundation +import Foundation +import RobinHood - class MockCrowdloanContributionConfirmViewProtocol: CrowdloanContributionConfirmViewProtocol, Cuckoo.ProtocolMock { + class MockDAppBrowserViewProtocol: DAppBrowserViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionConfirmViewProtocol + typealias MocksType = DAppBrowserViewProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmViewProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionConfirmViewProtocol + typealias Stubbing = __StubbingProxy_DAppBrowserViewProtocol + typealias Verification = __VerificationProxy_DAppBrowserViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionConfirmViewProtocol? + private var __defaultImplStub: DAppBrowserViewProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmViewProtocol) { + func enableDefaultImplementation(_ stub: DAppBrowserViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -8513,199 +8474,72 @@ import SoraFoundation } - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } - - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } - - } - - - - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } - - } - - func didReceiveAsset(viewModel: AssetBalanceViewModelProtocol) { - - return cuckoo_manager.call("didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) - - } - - - - func didReceiveFee(viewModel: BalanceViewModelProtocol?) { - - return cuckoo_manager.call("didReceiveFee(viewModel: BalanceViewModelProtocol?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) - - } - - - - func didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel) { - - return cuckoo_manager.call("didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveCrowdloan(viewModel: viewModel)) - - } - - - - func didReceiveEstimatedReward(viewModel: String?) { - - return cuckoo_manager.call("didReceiveEstimatedReward(viewModel: String?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveEstimatedReward(viewModel: viewModel)) - - } - - - - func didReceiveBonus(viewModel: String?) { - - return cuckoo_manager.call("didReceiveBonus(viewModel: String?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBonus(viewModel: viewModel)) - - } - - - - func didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM) { + func didReceive(viewModel: DAppBrowserModel) { - return cuckoo_manager.call("didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", + return cuckoo_manager.call("didReceive(viewModel: DAppBrowserModel)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveRewardDestination(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) } - public func applyLocalization() { + func didReceive(response: DAppScriptResponse, forTransport name: String) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(response: DAppScriptResponse, forTransport: String)", + parameters: (response, name), + escapingParameters: (response, name), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.didReceive(response: response, forTransport: name)) } - func didStartLoading() { + func didReceiveReplacement(transports: [DAppTransportModel], postExecution script: DAppScriptResponse) { - return cuckoo_manager.call("didStartLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", + parameters: (transports, script), + escapingParameters: (transports, script), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStartLoading()) + defaultCall: __defaultImplStub!.didReceiveReplacement(transports: transports, postExecution: script)) } - func didStopLoading() { + func didReceiveFavorite(flag: Bool) { - return cuckoo_manager.call("didStopLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveFavorite(flag: Bool)", + parameters: (flag), + escapingParameters: (flag), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopLoading()) + defaultCall: __defaultImplStub!.didReceiveFavorite(flag: flag)) } - struct __StubbingProxy_CrowdloanContributionConfirmViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppBrowserViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -8713,79 +8547,39 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") - } - - - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") - } - - - func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AssetBalanceViewModelProtocol)> where M1.MatchedType == AssetBalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AssetBalanceViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", parameterMatchers: matchers)) - } - - func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BalanceViewModelProtocol?)> where M1.OptionalMatchedType == BalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveFee(viewModel: BalanceViewModelProtocol?)", parameterMatchers: matchers)) - } - - func didReceiveCrowdloan(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributeConfirmViewModel)> where M1.MatchedType == CrowdloanContributeConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributeConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel)", parameterMatchers: matchers)) - } - - func didReceiveEstimatedReward(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveEstimatedReward(viewModel: String?)", parameterMatchers: matchers)) - } - - func didReceiveBonus(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveBonus(viewModel: String?)", parameterMatchers: matchers)) - } - - func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanRewardDestinationVM)> where M1.MatchedType == CrowdloanRewardDestinationVM { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanRewardDestinationVM)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", parameterMatchers: matchers)) + func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserModel)> where M1.MatchedType == DAppBrowserModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserViewProtocol.self, method: "didReceive(viewModel: DAppBrowserModel)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func didReceive(response: M1, forTransport name: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppScriptResponse, String)> where M1.MatchedType == DAppScriptResponse, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(DAppScriptResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserViewProtocol.self, method: "didReceive(response: DAppScriptResponse, forTransport: String)", parameterMatchers: matchers)) } - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + func didReceiveReplacement(transports: M1, postExecution script: M2) -> Cuckoo.ProtocolStubNoReturnFunction<([DAppTransportModel], DAppScriptResponse)> where M1.MatchedType == [DAppTransportModel], M2.MatchedType == DAppScriptResponse { + let matchers: [Cuckoo.ParameterMatcher<([DAppTransportModel], DAppScriptResponse)>] = [wrap(matchable: transports) { $0.0 }, wrap(matchable: script) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserViewProtocol.self, method: "didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", parameterMatchers: matchers)) } - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + func didReceiveFavorite(flag: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: flag) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserViewProtocol.self, method: "didReceiveFavorite(flag: Bool)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionConfirmViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppBrowserViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -8807,81 +8601,36 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(AssetBalanceViewModelProtocol), Void> where M1.MatchedType == AssetBalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AssetBalanceViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(BalanceViewModelProtocol?), Void> where M1.OptionalMatchedType == BalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveFee(viewModel: BalanceViewModelProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveCrowdloan(viewModel: M1) -> Cuckoo.__DoNotUse<(CrowdloanContributeConfirmViewModel), Void> where M1.MatchedType == CrowdloanContributeConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributeConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveEstimatedReward(viewModel: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveEstimatedReward(viewModel: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBonus(viewModel: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveBonus(viewModel: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.__DoNotUse<(CrowdloanRewardDestinationVM), Void> where M1.MatchedType == CrowdloanRewardDestinationVM { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanRewardDestinationVM)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(DAppBrowserModel), Void> where M1.MatchedType == DAppBrowserModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceive(viewModel: DAppBrowserModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(response: M1, forTransport name: M2) -> Cuckoo.__DoNotUse<(DAppScriptResponse, String), Void> where M1.MatchedType == DAppScriptResponse, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(DAppScriptResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] + return cuckoo_manager.verify("didReceive(response: DAppScriptResponse, forTransport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveReplacement(transports: M1, postExecution script: M2) -> Cuckoo.__DoNotUse<([DAppTransportModel], DAppScriptResponse), Void> where M1.MatchedType == [DAppTransportModel], M2.MatchedType == DAppScriptResponse { + let matchers: [Cuckoo.ParameterMatcher<([DAppTransportModel], DAppScriptResponse)>] = [wrap(matchable: transports) { $0.0 }, wrap(matchable: script) { $0.1 }] + return cuckoo_manager.verify("didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFavorite(flag: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: flag) { $0 }] + return cuckoo_manager.verify("didReceiveFavorite(flag: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionConfirmViewProtocolStub: CrowdloanContributionConfirmViewProtocol { + class DAppBrowserViewProtocolStub: DAppBrowserViewProtocol { @@ -8900,35 +8649,6 @@ import SoraFoundation } } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - - } - - - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } @@ -8936,55 +8656,25 @@ import SoraFoundation - func didReceiveAsset(viewModel: AssetBalanceViewModelProtocol) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(viewModel: BalanceViewModelProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveEstimatedReward(viewModel: String?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveBonus(viewModel: String?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM) { + func didReceive(viewModel: DAppBrowserModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func didReceive(response: DAppScriptResponse, forTransport name: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoading() { + func didReceiveReplacement(transports: [DAppTransportModel], postExecution script: DAppScriptResponse) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStopLoading() { + func didReceiveFavorite(flag: Bool) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -8992,19 +8682,19 @@ import SoraFoundation - class MockCrowdloanContributionConfirmPresenterProtocol: CrowdloanContributionConfirmPresenterProtocol, Cuckoo.ProtocolMock { + class MockDAppBrowserPresenterProtocol: DAppBrowserPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionConfirmPresenterProtocol + typealias MocksType = DAppBrowserPresenterProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmPresenterProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionConfirmPresenterProtocol + typealias Stubbing = __StubbingProxy_DAppBrowserPresenterProtocol + typealias Verification = __VerificationProxy_DAppBrowserPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionConfirmPresenterProtocol? + private var __defaultImplStub: DAppBrowserPresenterProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmPresenterProtocol) { + func enableDefaultImplementation(_ stub: DAppBrowserPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -9032,51 +8722,81 @@ import SoraFoundation - func confirm() { + func process(page: DAppBrowserPage) { - return cuckoo_manager.call("confirm()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("process(page: DAppBrowserPage)", + parameters: (page), + escapingParameters: (page), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.confirm()) + defaultCall: __defaultImplStub!.process(page: page)) } - func presentAccountOptions() { + func process(message: Any, host: String, transport name: String) { - return cuckoo_manager.call("presentAccountOptions()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("process(message: Any, host: String, transport: String)", + parameters: (message, host, name), + escapingParameters: (message, host, name), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentAccountOptions()) + defaultCall: __defaultImplStub!.process(message: message, host: host, transport: name)) } - func presentRewardDestination() { + func activateSearch(with query: String?) { - return cuckoo_manager.call("presentRewardDestination()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("activateSearch(with: String?)", + parameters: (query), + escapingParameters: (query), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentRewardDestination()) + defaultCall: __defaultImplStub!.activateSearch(with: query)) + + } + + + + func toggleFavorite() { + + return cuckoo_manager.call("toggleFavorite()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.toggleFavorite()) + + } + + + + func close() { + + return cuckoo_manager.call("close()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.close()) } - struct __StubbingProxy_CrowdloanContributionConfirmPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppBrowserPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -9086,27 +8806,37 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + func process(page: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserPage)> where M1.MatchedType == DAppBrowserPage { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserPage)>] = [wrap(matchable: page) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "process(page: DAppBrowserPage)", parameterMatchers: matchers)) } - func presentAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func process(message: M1, host: M2, transport name: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(Any, String, String)> where M1.MatchedType == Any, M2.MatchedType == String, M3.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(Any, String, String)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: host) { $0.1 }, wrap(matchable: name) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "process(message: Any, host: String, transport: String)", parameterMatchers: matchers)) + } + + func activateSearch(with query: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: query) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "activateSearch(with: String?)", parameterMatchers: matchers)) + } + + func toggleFavorite() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmPresenterProtocol.self, method: "presentAccountOptions()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "toggleFavorite()", parameterMatchers: matchers)) } - func presentRewardDestination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func close() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmPresenterProtocol.self, method: "presentRewardDestination()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "close()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionConfirmPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppBrowserPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -9127,27 +8857,39 @@ import SoraFoundation } @discardableResult - func confirm() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func process(page: M1) -> Cuckoo.__DoNotUse<(DAppBrowserPage), Void> where M1.MatchedType == DAppBrowserPage { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserPage)>] = [wrap(matchable: page) { $0 }] + return cuckoo_manager.verify("process(page: DAppBrowserPage)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { + func process(message: M1, host: M2, transport name: M3) -> Cuckoo.__DoNotUse<(Any, String, String), Void> where M1.MatchedType == Any, M2.MatchedType == String, M3.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(Any, String, String)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: host) { $0.1 }, wrap(matchable: name) { $0.2 }] + return cuckoo_manager.verify("process(message: Any, host: String, transport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func activateSearch(with query: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: query) { $0 }] + return cuckoo_manager.verify("activateSearch(with: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func toggleFavorite() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("toggleFavorite()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentRewardDestination() -> Cuckoo.__DoNotUse<(), Void> { + func close() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentRewardDestination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("close()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionConfirmPresenterProtocolStub: CrowdloanContributionConfirmPresenterProtocol { + class DAppBrowserPresenterProtocolStub: DAppBrowserPresenterProtocol { @@ -9161,19 +8903,31 @@ import SoraFoundation - func confirm() { + func process(page: DAppBrowserPage) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentAccountOptions() { + func process(message: Any, host: String, transport name: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentRewardDestination() { + func activateSearch(with query: String?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func toggleFavorite() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func close() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -9181,19 +8935,19 @@ import SoraFoundation - class MockCrowdloanContributionConfirmInteractorInputProtocol: CrowdloanContributionConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockDAppBrowserInteractorInputProtocol: DAppBrowserInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionConfirmInteractorInputProtocol + typealias MocksType = DAppBrowserInteractorInputProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmInteractorInputProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionConfirmInteractorInputProtocol + typealias Stubbing = __StubbingProxy_DAppBrowserInteractorInputProtocol + typealias Verification = __VerificationProxy_DAppBrowserInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionConfirmInteractorInputProtocol? + private var __defaultImplStub: DAppBrowserInteractorInputProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: DAppBrowserInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -9206,66 +8960,126 @@ import SoraFoundation - func estimateFee(for contribution: BigUInt) { + func setup() { - return cuckoo_manager.call("estimateFee(for: BigUInt)", - parameters: (contribution), - escapingParameters: (contribution), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFee(for: contribution)) + defaultCall: __defaultImplStub!.setup()) } - func submit(contribution: BigUInt) { + func process(host: String) { - return cuckoo_manager.call("submit(contribution: BigUInt)", - parameters: (contribution), - escapingParameters: (contribution), + return cuckoo_manager.call("process(host: String)", + parameters: (host), + escapingParameters: (host), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.submit(contribution: contribution)) + defaultCall: __defaultImplStub!.process(host: host)) } - func setup() { + func process(message: Any, host: String, transport name: String) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("process(message: Any, host: String, transport: String)", + parameters: (message, host, name), + escapingParameters: (message, host, name), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.process(message: message, host: host, transport: name)) } - func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { + func processConfirmation(response: DAppOperationResponse, forTransport name: String) { - return cuckoo_manager.call("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", - parameters: (amount, bonusService), - escapingParameters: (amount, bonusService), + return cuckoo_manager.call("processConfirmation(response: DAppOperationResponse, forTransport: String)", + parameters: (response, name), + escapingParameters: (response, name), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFee(for: amount, bonusService: bonusService)) + defaultCall: __defaultImplStub!.processConfirmation(response: response, forTransport: name)) + + } + + + + func process(newQuery: DAppSearchResult) { + + return cuckoo_manager.call("process(newQuery: DAppSearchResult)", + parameters: (newQuery), + escapingParameters: (newQuery), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.process(newQuery: newQuery)) + + } + + + + func processAuth(response: DAppAuthResponse, forTransport name: String) { + + return cuckoo_manager.call("processAuth(response: DAppAuthResponse, forTransport: String)", + parameters: (response, name), + escapingParameters: (response, name), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.processAuth(response: response, forTransport: name)) + + } + + + + func removeFromFavorites(record: DAppFavorite) { + + return cuckoo_manager.call("removeFromFavorites(record: DAppFavorite)", + parameters: (record), + escapingParameters: (record), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.removeFromFavorites(record: record)) + + } + + + + func reload() { + + return cuckoo_manager.call("reload()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.reload()) } - struct __StubbingProxy_CrowdloanContributionConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppBrowserInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -9273,29 +9087,49 @@ import SoraFoundation } - func estimateFee(for contribution: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt)> where M1.MatchedType == BigUInt { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt)>] = [wrap(matchable: contribution) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorInputProtocol.self, method: "estimateFee(for: BigUInt)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func submit(contribution: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt)> where M1.MatchedType == BigUInt { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt)>] = [wrap(matchable: contribution) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorInputProtocol.self, method: "submit(contribution: BigUInt)", parameterMatchers: matchers)) + func process(host: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: host) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "process(host: String)", parameterMatchers: matchers)) } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + func process(message: M1, host: M2, transport name: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(Any, String, String)> where M1.MatchedType == Any, M2.MatchedType == String, M3.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(Any, String, String)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: host) { $0.1 }, wrap(matchable: name) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "process(message: Any, host: String, transport: String)", parameterMatchers: matchers)) } - func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt, CrowdloanBonusServiceProtocol?)> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorInputProtocol.self, method: "estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) + func processConfirmation(response: M1, forTransport name: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationResponse, String)> where M1.MatchedType == DAppOperationResponse, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "processConfirmation(response: DAppOperationResponse, forTransport: String)", parameterMatchers: matchers)) + } + + func process(newQuery: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppSearchResult)> where M1.MatchedType == DAppSearchResult { + let matchers: [Cuckoo.ParameterMatcher<(DAppSearchResult)>] = [wrap(matchable: newQuery) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "process(newQuery: DAppSearchResult)", parameterMatchers: matchers)) + } + + func processAuth(response: M1, forTransport name: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthResponse, String)> where M1.MatchedType == DAppAuthResponse, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "processAuth(response: DAppAuthResponse, forTransport: String)", parameterMatchers: matchers)) + } + + func removeFromFavorites(record: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppFavorite)> where M1.MatchedType == DAppFavorite { + let matchers: [Cuckoo.ParameterMatcher<(DAppFavorite)>] = [wrap(matchable: record) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "removeFromFavorites(record: DAppFavorite)", parameterMatchers: matchers)) + } + + func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "reload()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppBrowserInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -9310,33 +9144,57 @@ import SoraFoundation @discardableResult - func estimateFee(for contribution: M1) -> Cuckoo.__DoNotUse<(BigUInt), Void> where M1.MatchedType == BigUInt { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt)>] = [wrap(matchable: contribution) { $0 }] - return cuckoo_manager.verify("estimateFee(for: BigUInt)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func submit(contribution: M1) -> Cuckoo.__DoNotUse<(BigUInt), Void> where M1.MatchedType == BigUInt { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt)>] = [wrap(matchable: contribution) { $0 }] - return cuckoo_manager.verify("submit(contribution: BigUInt)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func process(host: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: host) { $0 }] + return cuckoo_manager.verify("process(host: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func process(message: M1, host: M2, transport name: M3) -> Cuckoo.__DoNotUse<(Any, String, String), Void> where M1.MatchedType == Any, M2.MatchedType == String, M3.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(Any, String, String)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: host) { $0.1 }, wrap(matchable: name) { $0.2 }] + return cuckoo_manager.verify("process(message: Any, host: String, transport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.__DoNotUse<(BigUInt, CrowdloanBonusServiceProtocol?), Void> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] - return cuckoo_manager.verify("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func processConfirmation(response: M1, forTransport name: M2) -> Cuckoo.__DoNotUse<(DAppOperationResponse, String), Void> where M1.MatchedType == DAppOperationResponse, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] + return cuckoo_manager.verify("processConfirmation(response: DAppOperationResponse, forTransport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func process(newQuery: M1) -> Cuckoo.__DoNotUse<(DAppSearchResult), Void> where M1.MatchedType == DAppSearchResult { + let matchers: [Cuckoo.ParameterMatcher<(DAppSearchResult)>] = [wrap(matchable: newQuery) { $0 }] + return cuckoo_manager.verify("process(newQuery: DAppSearchResult)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func processAuth(response: M1, forTransport name: M2) -> Cuckoo.__DoNotUse<(DAppAuthResponse, String), Void> where M1.MatchedType == DAppAuthResponse, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] + return cuckoo_manager.verify("processAuth(response: DAppAuthResponse, forTransport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func removeFromFavorites(record: M1) -> Cuckoo.__DoNotUse<(DAppFavorite), Void> where M1.MatchedType == DAppFavorite { + let matchers: [Cuckoo.ParameterMatcher<(DAppFavorite)>] = [wrap(matchable: record) { $0 }] + return cuckoo_manager.verify("removeFromFavorites(record: DAppFavorite)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func reload() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionConfirmInteractorInputProtocolStub: CrowdloanContributionConfirmInteractorInputProtocol { + class DAppBrowserInteractorInputProtocolStub: DAppBrowserInteractorInputProtocol { @@ -9344,267 +9202,201 @@ import SoraFoundation - func estimateFee(for contribution: BigUInt) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func submit(contribution: BigUInt) { + func process(host: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func setup() { + func process(message: Any, host: String, transport name: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { + func processConfirmation(response: DAppOperationResponse, forTransport name: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockCrowdloanContributionConfirmInteractorOutputProtocol: CrowdloanContributionConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = CrowdloanContributionConfirmInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmInteractorOutputProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionConfirmInteractorOutputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: CrowdloanContributionConfirmInteractorOutputProtocol? - - func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmInteractorOutputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func process(newQuery: DAppSearchResult) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - + func processAuth(response: DAppAuthResponse, forTransport name: String) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func didSubmitContribution(result: Result) { - - return cuckoo_manager.call("didSubmitContribution(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didSubmitContribution(result: result)) - + func removeFromFavorites(record: DAppFavorite) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveDisplayAddress(result: Result) { - - return cuckoo_manager.call("didReceiveDisplayAddress(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveDisplayAddress(result: result)) - + func reload() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockDAppBrowserInteractorOutputProtocol: DAppBrowserInteractorOutputProtocol, Cuckoo.ProtocolMock { + typealias MocksType = DAppBrowserInteractorOutputProtocol - func didReceiveRewardDestinationAddress(_ address: AccountAddress) { - - return cuckoo_manager.call("didReceiveRewardDestinationAddress(_: AccountAddress)", - parameters: (address), - escapingParameters: (address), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveRewardDestinationAddress(address)) - + typealias Stubbing = __StubbingProxy_DAppBrowserInteractorOutputProtocol + typealias Verification = __VerificationProxy_DAppBrowserInteractorOutputProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: DAppBrowserInteractorOutputProtocol? + + func enableDefaultImplementation(_ stub: DAppBrowserInteractorOutputProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func didReceiveCrowdloan(result: Result) { - - return cuckoo_manager.call("didReceiveCrowdloan(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveCrowdloan(result: result)) - - } + - func didReceiveDisplayInfo(result: Result) { + func didReceive(error: Error) { - return cuckoo_manager.call("didReceiveDisplayInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceive(error: Error)", + parameters: (error), + escapingParameters: (error), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveDisplayInfo(result: result)) + defaultCall: __defaultImplStub!.didReceive(error: error)) } - func didReceiveAccountInfo(result: Result) { + func didReceiveDApp(model: DAppBrowserModel) { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveDApp(model: DAppBrowserModel)", + parameters: (model), + escapingParameters: (model), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.didReceiveDApp(model: model)) } - func didReceiveBlockNumber(result: Result) { + func didReceiveReplacement(transports: [DAppTransportModel], postExecution script: DAppScriptResponse) { - return cuckoo_manager.call("didReceiveBlockNumber(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", + parameters: (transports, script), + escapingParameters: (transports, script), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveBlockNumber(result: result)) + defaultCall: __defaultImplStub!.didReceiveReplacement(transports: transports, postExecution: script)) } - func didReceiveBlockDuration(result: Result) { + func didReceive(response: DAppScriptResponse, forTransport name: String) { - return cuckoo_manager.call("didReceiveBlockDuration(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceive(response: DAppScriptResponse, forTransport: String)", + parameters: (response, name), + escapingParameters: (response, name), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveBlockDuration(result: result)) + defaultCall: __defaultImplStub!.didReceive(response: response, forTransport: name)) } - func didReceiveLeasingPeriod(result: Result) { + func didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType) { - return cuckoo_manager.call("didReceiveLeasingPeriod(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType)", + parameters: (request, type), + escapingParameters: (request, type), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(result: result)) + defaultCall: __defaultImplStub!.didReceiveConfirmation(request: request, type: type)) } - func didReceiveLeasingOffset(result: Result) { + func didReceiveAuth(request: DAppAuthRequest) { - return cuckoo_manager.call("didReceiveLeasingOffset(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveAuth(request: DAppAuthRequest)", + parameters: (request), + escapingParameters: (request), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveLeasingOffset(result: result)) + defaultCall: __defaultImplStub!.didReceiveAuth(request: request)) } - func didReceiveMinimumBalance(result: Result) { + func didDetectPhishing(host: String) { - return cuckoo_manager.call("didReceiveMinimumBalance(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didDetectPhishing(host: String)", + parameters: (host), + escapingParameters: (host), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMinimumBalance(result: result)) + defaultCall: __defaultImplStub!.didDetectPhishing(host: host)) } - func didReceiveMinimumContribution(result: Result) { + func didReceiveFavorite(changes: [DataProviderChange]) { - return cuckoo_manager.call("didReceiveMinimumContribution(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveFavorite(changes: [DataProviderChange])", + parameters: (changes), + escapingParameters: (changes), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMinimumContribution(result: result)) - - } - - - - func didReceivePriceData(result: Result) { - - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) - - } - - - - func didReceiveFee(result: Result) { - - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + defaultCall: __defaultImplStub!.didReceiveFavorite(changes: changes)) } - struct __StubbingProxy_CrowdloanContributionConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppBrowserInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -9612,79 +9404,49 @@ import SoraFoundation } - func didSubmitContribution(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didSubmitContribution(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveDisplayAddress(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveDisplayAddress(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveRewardDestinationAddress(_ address: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: address) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveRewardDestinationAddress(_: AccountAddress)", parameterMatchers: matchers)) - } - - func didReceiveCrowdloan(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveCrowdloan(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveDisplayInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveDisplayInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveBlockNumber(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveBlockNumber(result: Result)", parameterMatchers: matchers)) + func didReceive(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceive(error: Error)", parameterMatchers: matchers)) } - func didReceiveBlockDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveBlockDuration(result: Result)", parameterMatchers: matchers)) + func didReceiveDApp(model: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserModel)> where M1.MatchedType == DAppBrowserModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserModel)>] = [wrap(matchable: model) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveDApp(model: DAppBrowserModel)", parameterMatchers: matchers)) } - func didReceiveLeasingPeriod(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(result: Result)", parameterMatchers: matchers)) + func didReceiveReplacement(transports: M1, postExecution script: M2) -> Cuckoo.ProtocolStubNoReturnFunction<([DAppTransportModel], DAppScriptResponse)> where M1.MatchedType == [DAppTransportModel], M2.MatchedType == DAppScriptResponse { + let matchers: [Cuckoo.ParameterMatcher<([DAppTransportModel], DAppScriptResponse)>] = [wrap(matchable: transports) { $0.0 }, wrap(matchable: script) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", parameterMatchers: matchers)) } - func didReceiveLeasingOffset(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(result: Result)", parameterMatchers: matchers)) + func didReceive(response: M1, forTransport name: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppScriptResponse, String)> where M1.MatchedType == DAppScriptResponse, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(DAppScriptResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceive(response: DAppScriptResponse, forTransport: String)", parameterMatchers: matchers)) } - func didReceiveMinimumBalance(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveMinimumBalance(result: Result)", parameterMatchers: matchers)) + func didReceiveConfirmation(request: M1, type: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationRequest, DAppSigningType)> where M1.MatchedType == DAppOperationRequest, M2.MatchedType == DAppSigningType { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationRequest, DAppSigningType)>] = [wrap(matchable: request) { $0.0 }, wrap(matchable: type) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType)", parameterMatchers: matchers)) } - func didReceiveMinimumContribution(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveMinimumContribution(result: Result)", parameterMatchers: matchers)) + func didReceiveAuth(request: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthRequest)> where M1.MatchedType == DAppAuthRequest { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthRequest)>] = [wrap(matchable: request) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveAuth(request: DAppAuthRequest)", parameterMatchers: matchers)) } - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + func didDetectPhishing(host: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: host) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didDetectPhishing(host: String)", parameterMatchers: matchers)) } - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + func didReceiveFavorite(changes: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([DataProviderChange])> where M1.MatchedType == [DataProviderChange] { + let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveFavorite(changes: [DataProviderChange])", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppBrowserInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -9699,93 +9461,57 @@ import SoraFoundation @discardableResult - func didSubmitContribution(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didSubmitContribution(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveDisplayAddress(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveDisplayAddress(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveRewardDestinationAddress(_ address: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: address) { $0 }] - return cuckoo_manager.verify("didReceiveRewardDestinationAddress(_: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveCrowdloan(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveCrowdloan(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveDisplayInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveDisplayInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBlockNumber(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBlockNumber(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return cuckoo_manager.verify("didReceive(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveBlockDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBlockDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveDApp(model: M1) -> Cuckoo.__DoNotUse<(DAppBrowserModel), Void> where M1.MatchedType == DAppBrowserModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserModel)>] = [wrap(matchable: model) { $0 }] + return cuckoo_manager.verify("didReceiveDApp(model: DAppBrowserModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveLeasingPeriod(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingPeriod(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveReplacement(transports: M1, postExecution script: M2) -> Cuckoo.__DoNotUse<([DAppTransportModel], DAppScriptResponse), Void> where M1.MatchedType == [DAppTransportModel], M2.MatchedType == DAppScriptResponse { + let matchers: [Cuckoo.ParameterMatcher<([DAppTransportModel], DAppScriptResponse)>] = [wrap(matchable: transports) { $0.0 }, wrap(matchable: script) { $0.1 }] + return cuckoo_manager.verify("didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveLeasingOffset(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingOffset(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(response: M1, forTransport name: M2) -> Cuckoo.__DoNotUse<(DAppScriptResponse, String), Void> where M1.MatchedType == DAppScriptResponse, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(DAppScriptResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] + return cuckoo_manager.verify("didReceive(response: DAppScriptResponse, forTransport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveMinimumBalance(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMinimumBalance(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveConfirmation(request: M1, type: M2) -> Cuckoo.__DoNotUse<(DAppOperationRequest, DAppSigningType), Void> where M1.MatchedType == DAppOperationRequest, M2.MatchedType == DAppSigningType { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationRequest, DAppSigningType)>] = [wrap(matchable: request) { $0.0 }, wrap(matchable: type) { $0.1 }] + return cuckoo_manager.verify("didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveMinimumContribution(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMinimumContribution(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAuth(request: M1) -> Cuckoo.__DoNotUse<(DAppAuthRequest), Void> where M1.MatchedType == DAppAuthRequest { + let matchers: [Cuckoo.ParameterMatcher<(DAppAuthRequest)>] = [wrap(matchable: request) { $0 }] + return cuckoo_manager.verify("didReceiveAuth(request: DAppAuthRequest)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didDetectPhishing(host: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: host) { $0 }] + return cuckoo_manager.verify("didDetectPhishing(host: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFavorite(changes: M1) -> Cuckoo.__DoNotUse<([DataProviderChange]), Void> where M1.MatchedType == [DataProviderChange] { + let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] + return cuckoo_manager.verify("didReceiveFavorite(changes: [DataProviderChange])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionConfirmInteractorOutputProtocolStub: CrowdloanContributionConfirmInteractorOutputProtocol { + class DAppBrowserInteractorOutputProtocolStub: DAppBrowserInteractorOutputProtocol { @@ -9793,85 +9519,49 @@ import SoraFoundation - func didSubmitContribution(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveDisplayAddress(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveRewardDestinationAddress(_ address: AccountAddress) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveCrowdloan(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveDisplayInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAccountInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveBlockNumber(result: Result) { + func didReceive(error: Error) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveBlockDuration(result: Result) { + func didReceiveDApp(model: DAppBrowserModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveLeasingPeriod(result: Result) { + func didReceiveReplacement(transports: [DAppTransportModel], postExecution script: DAppScriptResponse) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveLeasingOffset(result: Result) { + func didReceive(response: DAppScriptResponse, forTransport name: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveMinimumBalance(result: Result) { + func didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveMinimumContribution(result: Result) { + func didReceiveAuth(request: DAppAuthRequest) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceivePriceData(result: Result) { + func didDetectPhishing(host: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveFee(result: Result) { + func didReceiveFavorite(changes: [DataProviderChange]) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -9879,19 +9569,19 @@ import SoraFoundation - class MockCrowdloanContributionConfirmWireframeProtocol: CrowdloanContributionConfirmWireframeProtocol, Cuckoo.ProtocolMock { + class MockDAppBrowserWireframeProtocol: DAppBrowserWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionConfirmWireframeProtocol + typealias MocksType = DAppBrowserWireframeProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmWireframeProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionConfirmWireframeProtocol + typealias Stubbing = __StubbingProxy_DAppBrowserWireframeProtocol + typealias Verification = __VerificationProxy_DAppBrowserWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionConfirmWireframeProtocol? + private var __defaultImplStub: DAppBrowserWireframeProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmWireframeProtocol) { + func enableDefaultImplementation(_ stub: DAppBrowserWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -9904,51 +9594,96 @@ import SoraFoundation - func complete(on view: CrowdloanContributionConfirmViewProtocol?) { + func presentOperationConfirm(from view: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate) { - return cuckoo_manager.call("complete(on: CrowdloanContributionConfirmViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("presentOperationConfirm(from: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate)", + parameters: (view, request, type, delegate), + escapingParameters: (view, request, type, delegate), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.complete(on: view)) + defaultCall: __defaultImplStub!.presentOperationConfirm(from: view, request: request, type: type, delegate: delegate)) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func presentSearch(from view: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("presentSearch(from: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate)", + parameters: (view, initialQuery, delegate), + escapingParameters: (view, initialQuery, delegate), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.presentSearch(from: view, initialQuery: initialQuery, delegate: delegate)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func presentAuth(from view: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate) { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("presentAuth(from: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate)", + parameters: (view, request, delegate), + escapingParameters: (view, request, delegate), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.presentAuth(from: view, request: request, delegate: delegate)) + + } + + + + func presentPhishingDetected(from view: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate) { + + return cuckoo_manager.call("presentPhishingDetected(from: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate)", + parameters: (view, delegate), + escapingParameters: (view, delegate), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentPhishingDetected(from: view, delegate: delegate)) + + } + + + + func presentAddToFavoriteForm(from view: DAppBrowserViewProtocol?, page: DAppBrowserPage) { + + return cuckoo_manager.call("presentAddToFavoriteForm(from: DAppBrowserViewProtocol?, page: DAppBrowserPage)", + parameters: (view, page), + escapingParameters: (view, page), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentAddToFavoriteForm(from: view, page: page)) + + } + + + + func close(view: DAppBrowserViewProtocol?) { + + return cuckoo_manager.call("close(view: DAppBrowserViewProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.close(view: view)) } - struct __StubbingProxy_CrowdloanContributionConfirmWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppBrowserWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -9956,24 +9691,39 @@ import SoraFoundation } - func complete(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributionConfirmViewProtocol?)> where M1.OptionalMatchedType == CrowdloanContributionConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmWireframeProtocol.self, method: "complete(on: CrowdloanContributionConfirmViewProtocol?)", parameterMatchers: matchers)) + func presentOperationConfirm(from view: M1, request: M2, type: M3, delegate: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, DAppOperationRequest, DAppSigningType, DAppOperationConfirmDelegate)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppOperationRequest, M3.MatchedType == DAppSigningType, M4.MatchedType == DAppOperationConfirmDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppOperationRequest, DAppSigningType, DAppOperationConfirmDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: request) { $0.1 }, wrap(matchable: type) { $0.2 }, wrap(matchable: delegate) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentOperationConfirm(from: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate)", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func presentSearch(from view: M1, initialQuery: M2, delegate: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, String?, DAppSearchDelegate)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.OptionalMatchedType == String, M3.MatchedType == DAppSearchDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, String?, DAppSearchDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: initialQuery) { $0.1 }, wrap(matchable: delegate) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentSearch(from: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate)", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func presentAuth(from view: M1, request: M2, delegate: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, DAppAuthRequest, DAppAuthDelegate)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppAuthRequest, M3.MatchedType == DAppAuthDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppAuthRequest, DAppAuthDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: request) { $0.1 }, wrap(matchable: delegate) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentAuth(from: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate)", parameterMatchers: matchers)) + } + + func presentPhishingDetected(from view: M1, delegate: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, DAppPhishingViewDelegate)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppPhishingViewDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppPhishingViewDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentPhishingDetected(from: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate)", parameterMatchers: matchers)) + } + + func presentAddToFavoriteForm(from view: M1, page: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, DAppBrowserPage)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppBrowserPage { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppBrowserPage)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: page) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentAddToFavoriteForm(from: DAppBrowserViewProtocol?, page: DAppBrowserPage)", parameterMatchers: matchers)) + } + + func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?)> where M1.OptionalMatchedType == DAppBrowserViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "close(view: DAppBrowserViewProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionConfirmWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppBrowserWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -9988,27 +9738,45 @@ import SoraFoundation @discardableResult - func complete(on view: M1) -> Cuckoo.__DoNotUse<(CrowdloanContributionConfirmViewProtocol?), Void> where M1.OptionalMatchedType == CrowdloanContributionConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("complete(on: CrowdloanContributionConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentOperationConfirm(from view: M1, request: M2, type: M3, delegate: M4) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, DAppOperationRequest, DAppSigningType, DAppOperationConfirmDelegate), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppOperationRequest, M3.MatchedType == DAppSigningType, M4.MatchedType == DAppOperationConfirmDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppOperationRequest, DAppSigningType, DAppOperationConfirmDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: request) { $0.1 }, wrap(matchable: type) { $0.2 }, wrap(matchable: delegate) { $0.3 }] + return cuckoo_manager.verify("presentOperationConfirm(from: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentSearch(from view: M1, initialQuery: M2, delegate: M3) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, String?, DAppSearchDelegate), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.OptionalMatchedType == String, M3.MatchedType == DAppSearchDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, String?, DAppSearchDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: initialQuery) { $0.1 }, wrap(matchable: delegate) { $0.2 }] + return cuckoo_manager.verify("presentSearch(from: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentAuth(from view: M1, request: M2, delegate: M3) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, DAppAuthRequest, DAppAuthDelegate), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppAuthRequest, M3.MatchedType == DAppAuthDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppAuthRequest, DAppAuthDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: request) { $0.1 }, wrap(matchable: delegate) { $0.2 }] + return cuckoo_manager.verify("presentAuth(from: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentPhishingDetected(from view: M1, delegate: M2) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, DAppPhishingViewDelegate), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppPhishingViewDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppPhishingViewDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }] + return cuckoo_manager.verify("presentPhishingDetected(from: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentAddToFavoriteForm(from view: M1, page: M2) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, DAppBrowserPage), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppBrowserPage { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppBrowserPage)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: page) { $0.1 }] + return cuckoo_manager.verify("presentAddToFavoriteForm(from: DAppBrowserViewProtocol?, page: DAppBrowserPage)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func close(view: M1) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(view: DAppBrowserViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionConfirmWireframeProtocolStub: CrowdloanContributionConfirmWireframeProtocol { + class DAppBrowserWireframeProtocolStub: DAppBrowserWireframeProtocol { @@ -10016,19 +9784,37 @@ import SoraFoundation - func complete(on view: CrowdloanContributionConfirmViewProtocol?) { + func presentOperationConfirm(from view: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func presentSearch(from view: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func presentAuth(from view: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentPhishingDetected(from view: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentAddToFavoriteForm(from view: DAppBrowserViewProtocol?, page: DAppBrowserPage) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func close(view: DAppBrowserViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -10038,25 +9824,23 @@ import SoraFoundation import Cuckoo @testable import novawallet -import BigInt -import CommonWallet -import Foundation -import SoraFoundation +import RobinHood +import SubstrateSdk - class MockCrowdloanContributionSetupViewProtocol: CrowdloanContributionSetupViewProtocol, Cuckoo.ProtocolMock { + class MockDAppListViewProtocol: DAppListViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionSetupViewProtocol + typealias MocksType = DAppListViewProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupViewProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionSetupViewProtocol + typealias Stubbing = __StubbingProxy_DAppListViewProtocol + typealias Verification = __VerificationProxy_DAppListViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionSetupViewProtocol? + private var __defaultImplStub: DAppListViewProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionSetupViewProtocol) { + func enableDefaultImplementation(_ stub: DAppListViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -10091,214 +9875,57 @@ import SoraFoundation } - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } - - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } - - } - - - - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } - - } - - func didReceiveAsset(viewModel: AssetBalanceViewModelProtocol) { + func didReceiveWalletSwitch(viewModel: WalletSwitchViewModel) { - return cuckoo_manager.call("didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", + return cuckoo_manager.call("didReceiveWalletSwitch(viewModel: WalletSwitchViewModel)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveWalletSwitch(viewModel: viewModel)) } - func didReceiveFee(viewModel: BalanceViewModelProtocol?) { + func didReceive(state: DAppListState) { - return cuckoo_manager.call("didReceiveFee(viewModel: BalanceViewModelProtocol?)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didReceive(state: DAppListState)", + parameters: (state), + escapingParameters: (state), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceive(state: state)) } - func didReceiveInput(viewModel: AmountInputViewModelProtocol) { + func didCompleteRefreshing() { - return cuckoo_manager.call("didReceiveInput(viewModel: AmountInputViewModelProtocol)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) - - } - - - - func didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel) { - - return cuckoo_manager.call("didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveCrowdloan(viewModel: viewModel)) - - } - - - - func didReceiveEstimatedReward(viewModel: String?) { - - return cuckoo_manager.call("didReceiveEstimatedReward(viewModel: String?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveEstimatedReward(viewModel: viewModel)) - - } - - - - func didReceiveBonus(viewModel: String?) { - - return cuckoo_manager.call("didReceiveBonus(viewModel: String?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBonus(viewModel: viewModel)) - - } - - - - func didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM) { - - return cuckoo_manager.call("didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveRewardDestination(viewModel: viewModel)) - - } - - - - public func applyLocalization() { - - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.applyLocalization()) - - } - - - - func didStartLoading() { - - return cuckoo_manager.call("didStartLoading()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didStartLoading()) - - } - - - - func didStopLoading() { - - return cuckoo_manager.call("didStopLoading()", + return cuckoo_manager.call("didCompleteRefreshing()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopLoading()) + defaultCall: __defaultImplStub!.didCompleteRefreshing()) } - struct __StubbingProxy_CrowdloanContributionSetupViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppListViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -10306,84 +9933,34 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") - } - - - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") - } - - - func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AssetBalanceViewModelProtocol)> where M1.MatchedType == AssetBalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AssetBalanceViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", parameterMatchers: matchers)) - } - - func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BalanceViewModelProtocol?)> where M1.OptionalMatchedType == BalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveFee(viewModel: BalanceViewModelProtocol?)", parameterMatchers: matchers)) - } - - func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AmountInputViewModelProtocol)> where M1.MatchedType == AmountInputViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AmountInputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveInput(viewModel: AmountInputViewModelProtocol)", parameterMatchers: matchers)) - } - - func didReceiveCrowdloan(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributionSetupViewModel)> where M1.MatchedType == CrowdloanContributionSetupViewModel { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel)", parameterMatchers: matchers)) - } - - func didReceiveEstimatedReward(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveEstimatedReward(viewModel: String?)", parameterMatchers: matchers)) - } - - func didReceiveBonus(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveBonus(viewModel: String?)", parameterMatchers: matchers)) - } - - func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanRewardDestinationVM)> where M1.MatchedType == CrowdloanRewardDestinationVM { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanRewardDestinationVM)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", parameterMatchers: matchers)) - } - - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func didReceiveWalletSwitch(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(WalletSwitchViewModel)> where M1.MatchedType == WalletSwitchViewModel { + let matchers: [Cuckoo.ParameterMatcher<(WalletSwitchViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListViewProtocol.self, method: "didReceiveWalletSwitch(viewModel: WalletSwitchViewModel)", parameterMatchers: matchers)) } - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + func didReceive(state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppListState)> where M1.MatchedType == DAppListState { + let matchers: [Cuckoo.ParameterMatcher<(DAppListState)>] = [wrap(matchable: state) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListViewProtocol.self, method: "didReceive(state: DAppListState)", parameterMatchers: matchers)) } - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func didCompleteRefreshing() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppListViewProtocol.self, method: "didCompleteRefreshing()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionSetupViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppListViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -10405,87 +9982,30 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(AssetBalanceViewModelProtocol), Void> where M1.MatchedType == AssetBalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AssetBalanceViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(BalanceViewModelProtocol?), Void> where M1.OptionalMatchedType == BalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveFee(viewModel: BalanceViewModelProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(AmountInputViewModelProtocol), Void> where M1.MatchedType == AmountInputViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AmountInputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveInput(viewModel: AmountInputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveCrowdloan(viewModel: M1) -> Cuckoo.__DoNotUse<(CrowdloanContributionSetupViewModel), Void> where M1.MatchedType == CrowdloanContributionSetupViewModel { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveEstimatedReward(viewModel: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveEstimatedReward(viewModel: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBonus(viewModel: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveBonus(viewModel: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.__DoNotUse<(CrowdloanRewardDestinationVM), Void> where M1.MatchedType == CrowdloanRewardDestinationVM { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanRewardDestinationVM)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveWalletSwitch(viewModel: M1) -> Cuckoo.__DoNotUse<(WalletSwitchViewModel), Void> where M1.MatchedType == WalletSwitchViewModel { + let matchers: [Cuckoo.ParameterMatcher<(WalletSwitchViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveWalletSwitch(viewModel: WalletSwitchViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(state: M1) -> Cuckoo.__DoNotUse<(DAppListState), Void> where M1.MatchedType == DAppListState { + let matchers: [Cuckoo.ParameterMatcher<(DAppListState)>] = [wrap(matchable: state) { $0 }] + return cuckoo_manager.verify("didReceive(state: DAppListState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + func didCompleteRefreshing() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("didCompleteRefreshing()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionSetupViewProtocolStub: CrowdloanContributionSetupViewProtocol { + class DAppListViewProtocolStub: DAppListViewProtocol { @@ -10504,35 +10024,6 @@ import SoraFoundation } } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - - } - - - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } @@ -10540,61 +10031,19 @@ import SoraFoundation - func didReceiveAsset(viewModel: AssetBalanceViewModelProtocol) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(viewModel: BalanceViewModelProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveInput(viewModel: AmountInputViewModelProtocol) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveEstimatedReward(viewModel: String?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveBonus(viewModel: String?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - public func applyLocalization() { + func didReceiveWalletSwitch(viewModel: WalletSwitchViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoading() { + func didReceive(state: DAppListState) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStopLoading() { + func didCompleteRefreshing() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -10602,19 +10051,19 @@ import SoraFoundation - class MockCrowdloanContributionSetupPresenterProtocol: CrowdloanContributionSetupPresenterProtocol, Cuckoo.ProtocolMock { + class MockDAppListPresenterProtocol: DAppListPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionSetupPresenterProtocol + typealias MocksType = DAppListPresenterProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupPresenterProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionSetupPresenterProtocol + typealias Stubbing = __StubbingProxy_DAppListPresenterProtocol + typealias Verification = __VerificationProxy_DAppListPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionSetupPresenterProtocol? + private var __defaultImplStub: DAppListPresenterProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionSetupPresenterProtocol) { + func enableDefaultImplementation(_ stub: DAppListPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -10642,96 +10091,186 @@ import SoraFoundation - func selectAmountPercentage(_ percentage: Float) { + func refresh() { - return cuckoo_manager.call("selectAmountPercentage(_: Float)", - parameters: (percentage), - escapingParameters: (percentage), + return cuckoo_manager.call("refresh()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectAmountPercentage(percentage)) + defaultCall: __defaultImplStub!.refresh()) } - func updateAmount(_ newValue: Decimal) { + func activateAccount() { - return cuckoo_manager.call("updateAmount(_: Decimal)", - parameters: (newValue), - escapingParameters: (newValue), + return cuckoo_manager.call("activateAccount()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.updateAmount(newValue)) + defaultCall: __defaultImplStub!.activateAccount()) } - func proceed() { + func activateSearch() { - return cuckoo_manager.call("proceed()", + return cuckoo_manager.call("activateSearch()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.activateSearch()) } - func presentLearnMore() { + func activateSettings() { - return cuckoo_manager.call("presentLearnMore()", + return cuckoo_manager.call("activateSettings()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentLearnMore()) + defaultCall: __defaultImplStub!.activateSettings()) } - func presentAdditionalBonuses() { + func numberOfCategories() -> Int { - return cuckoo_manager.call("presentAdditionalBonuses()", + return cuckoo_manager.call("numberOfCategories() -> Int", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentAdditionalBonuses()) + defaultCall: __defaultImplStub!.numberOfCategories()) } - func presentRewardDestination() { + func category(at index: Int) -> String { - return cuckoo_manager.call("presentRewardDestination()", + return cuckoo_manager.call("category(at: Int) -> String", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.category(at: index)) + + } + + + + func selectedCategoryIndex() -> Int { + + return cuckoo_manager.call("selectedCategoryIndex() -> Int", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentRewardDestination()) + defaultCall: __defaultImplStub!.selectedCategoryIndex()) + + } + + + + func selectCategory(at index: Int) { + + return cuckoo_manager.call("selectCategory(at: Int)", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.selectCategory(at: index)) + + } + + + + func numberOfDApps() -> Int { + + return cuckoo_manager.call("numberOfDApps() -> Int", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.numberOfDApps()) + + } + + + + func dApp(at index: Int) -> DAppViewModel { + + return cuckoo_manager.call("dApp(at: Int) -> DAppViewModel", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.dApp(at: index)) + + } + + + + func selectDApp(at index: Int) { + + return cuckoo_manager.call("selectDApp(at: Int)", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.selectDApp(at: index)) + + } + + + + func toogleFavoriteForDApp(at index: Int) { + + return cuckoo_manager.call("toogleFavoriteForDApp(at: Int)", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.toogleFavoriteForDApp(at: index)) } - struct __StubbingProxy_CrowdloanContributionSetupPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppListPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -10741,42 +10280,72 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func selectAmountPercentage(_ percentage: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Float)> where M1.MatchedType == Float { - let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "selectAmountPercentage(_: Float)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func updateAmount(_ newValue: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "updateAmount(_: Decimal)", parameterMatchers: matchers)) + func refresh() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "refresh()", parameterMatchers: matchers)) } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func activateAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "activateAccount()", parameterMatchers: matchers)) } - func presentLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func activateSearch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "presentLearnMore()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "activateSearch()", parameterMatchers: matchers)) } - func presentAdditionalBonuses() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func activateSettings() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "presentAdditionalBonuses()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "activateSettings()", parameterMatchers: matchers)) } - func presentRewardDestination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func numberOfCategories() -> Cuckoo.ProtocolStubFunction<(), Int> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "presentRewardDestination()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "numberOfCategories() -> Int", parameterMatchers: matchers)) + } + + func category(at index: M1) -> Cuckoo.ProtocolStubFunction<(Int), String> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "category(at: Int) -> String", parameterMatchers: matchers)) + } + + func selectedCategoryIndex() -> Cuckoo.ProtocolStubFunction<(), Int> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "selectedCategoryIndex() -> Int", parameterMatchers: matchers)) + } + + func selectCategory(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "selectCategory(at: Int)", parameterMatchers: matchers)) + } + + func numberOfDApps() -> Cuckoo.ProtocolStubFunction<(), Int> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "numberOfDApps() -> Int", parameterMatchers: matchers)) + } + + func dApp(at index: M1) -> Cuckoo.ProtocolStubFunction<(Int), DAppViewModel> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "dApp(at: Int) -> DAppViewModel", parameterMatchers: matchers)) + } + + func selectDApp(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "selectDApp(at: Int)", parameterMatchers: matchers)) + } + + func toogleFavoriteForDApp(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "toogleFavoriteForDApp(at: Int)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionSetupPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppListPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -10797,45 +10366,81 @@ import SoraFoundation } @discardableResult - func selectAmountPercentage(_ percentage: M1) -> Cuckoo.__DoNotUse<(Float), Void> where M1.MatchedType == Float { - let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] - return cuckoo_manager.verify("selectAmountPercentage(_: Float)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func refresh() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("refresh()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func updateAmount(_ newValue: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] - return cuckoo_manager.verify("updateAmount(_: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func activateAccount() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("activateAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { + func activateSearch() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("activateSearch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentLearnMore() -> Cuckoo.__DoNotUse<(), Void> { + func activateSettings() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("activateSettings()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentAdditionalBonuses() -> Cuckoo.__DoNotUse<(), Void> { + func numberOfCategories() -> Cuckoo.__DoNotUse<(), Int> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentAdditionalBonuses()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("numberOfCategories() -> Int", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentRewardDestination() -> Cuckoo.__DoNotUse<(), Void> { + func category(at index: M1) -> Cuckoo.__DoNotUse<(Int), String> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("category(at: Int) -> String", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func selectedCategoryIndex() -> Cuckoo.__DoNotUse<(), Int> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentRewardDestination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("selectedCategoryIndex() -> Int", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func selectCategory(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("selectCategory(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func numberOfDApps() -> Cuckoo.__DoNotUse<(), Int> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("numberOfDApps() -> Int", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func dApp(at index: M1) -> Cuckoo.__DoNotUse<(Int), DAppViewModel> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("dApp(at: Int) -> DAppViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func selectDApp(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("selectDApp(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func toogleFavoriteForDApp(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("toogleFavoriteForDApp(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionSetupPresenterProtocolStub: CrowdloanContributionSetupPresenterProtocol { + class DAppListPresenterProtocolStub: DAppListPresenterProtocol { @@ -10849,37 +10454,73 @@ import SoraFoundation - func selectAmountPercentage(_ percentage: Float) { + func refresh() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func updateAmount(_ newValue: Decimal) { + func activateAccount() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func proceed() { + func activateSearch() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentLearnMore() { + func activateSettings() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentAdditionalBonuses() { + func numberOfCategories() -> Int { + return DefaultValueRegistry.defaultValue(for: (Int).self) + } + + + + func category(at index: Int) -> String { + return DefaultValueRegistry.defaultValue(for: (String).self) + } + + + + func selectedCategoryIndex() -> Int { + return DefaultValueRegistry.defaultValue(for: (Int).self) + } + + + + func selectCategory(at index: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentRewardDestination() { + func numberOfDApps() -> Int { + return DefaultValueRegistry.defaultValue(for: (Int).self) + } + + + + func dApp(at index: Int) -> DAppViewModel { + return DefaultValueRegistry.defaultValue(for: (DAppViewModel).self) + } + + + + func selectDApp(at index: Int) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func toogleFavoriteForDApp(at index: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -10887,19 +10528,19 @@ import SoraFoundation - class MockCrowdloanContributionSetupInteractorInputProtocol: CrowdloanContributionSetupInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockDAppListInteractorInputProtocol: DAppListInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionSetupInteractorInputProtocol + typealias MocksType = DAppListInteractorInputProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupInteractorInputProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionSetupInteractorInputProtocol + typealias Stubbing = __StubbingProxy_DAppListInteractorInputProtocol + typealias Verification = __VerificationProxy_DAppListInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionSetupInteractorInputProtocol? + private var __defaultImplStub: DAppListInteractorInputProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionSetupInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: DAppListInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -10927,21 +10568,51 @@ import SoraFoundation - func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { + func refresh() { - return cuckoo_manager.call("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", - parameters: (amount, bonusService), - escapingParameters: (amount, bonusService), + return cuckoo_manager.call("refresh()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFee(for: amount, bonusService: bonusService)) + defaultCall: __defaultImplStub!.refresh()) + + } + + + + func addToFavorites(dApp: DApp) { + + return cuckoo_manager.call("addToFavorites(dApp: DApp)", + parameters: (dApp), + escapingParameters: (dApp), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.addToFavorites(dApp: dApp)) + + } + + + + func removeFromFavorites(dAppIdentifier: String) { + + return cuckoo_manager.call("removeFromFavorites(dAppIdentifier: String)", + parameters: (dAppIdentifier), + escapingParameters: (dAppIdentifier), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.removeFromFavorites(dAppIdentifier: dAppIdentifier)) } - struct __StubbingProxy_CrowdloanContributionSetupInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppListInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -10951,17 +10622,27 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt, CrowdloanBonusServiceProtocol?)> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorInputProtocol.self, method: "estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) + func refresh() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorInputProtocol.self, method: "refresh()", parameterMatchers: matchers)) + } + + func addToFavorites(dApp: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DApp)> where M1.MatchedType == DApp { + let matchers: [Cuckoo.ParameterMatcher<(DApp)>] = [wrap(matchable: dApp) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorInputProtocol.self, method: "addToFavorites(dApp: DApp)", parameterMatchers: matchers)) + } + + func removeFromFavorites(dAppIdentifier: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: dAppIdentifier) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorInputProtocol.self, method: "removeFromFavorites(dAppIdentifier: String)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionSetupInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppListInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -10982,15 +10663,27 @@ import SoraFoundation } @discardableResult - func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.__DoNotUse<(BigUInt, CrowdloanBonusServiceProtocol?), Void> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] - return cuckoo_manager.verify("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func refresh() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("refresh()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func addToFavorites(dApp: M1) -> Cuckoo.__DoNotUse<(DApp), Void> where M1.MatchedType == DApp { + let matchers: [Cuckoo.ParameterMatcher<(DApp)>] = [wrap(matchable: dApp) { $0 }] + return cuckoo_manager.verify("addToFavorites(dApp: DApp)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func removeFromFavorites(dAppIdentifier: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: dAppIdentifier) { $0 }] + return cuckoo_manager.verify("removeFromFavorites(dAppIdentifier: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionSetupInteractorInputProtocolStub: CrowdloanContributionSetupInteractorInputProtocol { + class DAppListInteractorInputProtocolStub: DAppListInteractorInputProtocol { @@ -11004,7 +10697,19 @@ import SoraFoundation - func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { + func refresh() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func addToFavorites(dApp: DApp) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func removeFromFavorites(dAppIdentifier: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -11012,19 +10717,19 @@ import SoraFoundation - class MockCrowdloanContributionSetupInteractorOutputProtocol: CrowdloanContributionSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockDAppListInteractorOutputProtocol: DAppListInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionSetupInteractorOutputProtocol + typealias MocksType = DAppListInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupInteractorOutputProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionSetupInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_DAppListInteractorOutputProtocol + typealias Verification = __VerificationProxy_DAppListInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionSetupInteractorOutputProtocol? + private var __defaultImplStub: DAppListInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionSetupInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: DAppListInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -11037,171 +10742,223 @@ import SoraFoundation - func didReceiveCrowdloan(result: Result) { + func didReceive(walletResult: Result) { - return cuckoo_manager.call("didReceiveCrowdloan(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceive(walletResult: Result)", + parameters: (walletResult), + escapingParameters: (walletResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveCrowdloan(result: result)) + defaultCall: __defaultImplStub!.didReceive(walletResult: walletResult)) } - func didReceiveDisplayInfo(result: Result) { + func didReceive(dAppsResult: Result?) { - return cuckoo_manager.call("didReceiveDisplayInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceive(dAppsResult: Result?)", + parameters: (dAppsResult), + escapingParameters: (dAppsResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveDisplayInfo(result: result)) + defaultCall: __defaultImplStub!.didReceive(dAppsResult: dAppsResult)) } - func didReceiveAccountInfo(result: Result) { + func didReceiveFavoriteDapp(changes: [DataProviderChange]) { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveFavoriteDapp(changes: [DataProviderChange])", + parameters: (changes), + escapingParameters: (changes), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.didReceiveFavoriteDapp(changes: changes)) } + + struct __StubbingProxy_DAppListInteractorOutputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func didReceive(walletResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: walletResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorOutputProtocol.self, method: "didReceive(walletResult: Result)", parameterMatchers: matchers)) + } + + func didReceive(dAppsResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result?)> where M1.OptionalMatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result?)>] = [wrap(matchable: dAppsResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorOutputProtocol.self, method: "didReceive(dAppsResult: Result?)", parameterMatchers: matchers)) + } + + func didReceiveFavoriteDapp(changes: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([DataProviderChange])> where M1.MatchedType == [DataProviderChange] { + let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorOutputProtocol.self, method: "didReceiveFavoriteDapp(changes: [DataProviderChange])", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_DAppListInteractorOutputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func didReceive(walletResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: walletResult) { $0 }] + return cuckoo_manager.verify("didReceive(walletResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(dAppsResult: M1) -> Cuckoo.__DoNotUse<(Result?), Void> where M1.OptionalMatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result?)>] = [wrap(matchable: dAppsResult) { $0 }] + return cuckoo_manager.verify("didReceive(dAppsResult: Result?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveFavoriteDapp(changes: M1) -> Cuckoo.__DoNotUse<([DataProviderChange]), Void> where M1.MatchedType == [DataProviderChange] { + let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] + return cuckoo_manager.verify("didReceiveFavoriteDapp(changes: [DataProviderChange])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class DAppListInteractorOutputProtocolStub: DAppListInteractorOutputProtocol { + + + - func didReceiveBlockNumber(result: Result) { - - return cuckoo_manager.call("didReceiveBlockNumber(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBlockNumber(result: result)) - + + + func didReceive(walletResult: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveBlockDuration(result: Result) { - - return cuckoo_manager.call("didReceiveBlockDuration(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBlockDuration(result: result)) - + func didReceive(dAppsResult: Result?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveLeasingPeriod(result: Result) { - - return cuckoo_manager.call("didReceiveLeasingPeriod(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(result: result)) - + func didReceiveFavoriteDapp(changes: [DataProviderChange]) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockDAppListWireframeProtocol: DAppListWireframeProtocol, Cuckoo.ProtocolMock { + typealias MocksType = DAppListWireframeProtocol - func didReceiveLeasingOffset(result: Result) { - - return cuckoo_manager.call("didReceiveLeasingOffset(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveLeasingOffset(result: result)) - + typealias Stubbing = __StubbingProxy_DAppListWireframeProtocol + typealias Verification = __VerificationProxy_DAppListWireframeProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: DAppListWireframeProtocol? + + func enableDefaultImplementation(_ stub: DAppListWireframeProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + + + - func didReceiveMinimumBalance(result: Result) { + + + func showSearch(from view: DAppListViewProtocol?, delegate: DAppSearchDelegate) { - return cuckoo_manager.call("didReceiveMinimumBalance(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("showSearch(from: DAppListViewProtocol?, delegate: DAppSearchDelegate)", + parameters: (view, delegate), + escapingParameters: (view, delegate), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMinimumBalance(result: result)) + defaultCall: __defaultImplStub!.showSearch(from: view, delegate: delegate)) } - func didReceiveMinimumContribution(result: Result) { + func showBrowser(from view: DAppListViewProtocol?, for result: DAppSearchResult) { - return cuckoo_manager.call("didReceiveMinimumContribution(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("showBrowser(from: DAppListViewProtocol?, for: DAppSearchResult)", + parameters: (view, result), + escapingParameters: (view, result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMinimumContribution(result: result)) + defaultCall: __defaultImplStub!.showBrowser(from: view, for: result)) } - func didReceivePriceData(result: Result) { + func showSetting(from view: DAppListViewProtocol?) { - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("showSetting(from: DAppListViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + defaultCall: __defaultImplStub!.showSetting(from: view)) } - func didReceiveFee(result: Result) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", + parameters: (url, view, style), + escapingParameters: (url, view, style), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) } - struct __StubbingProxy_CrowdloanContributionSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppListWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -11209,64 +10966,29 @@ import SoraFoundation } - func didReceiveCrowdloan(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveCrowdloan(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveDisplayInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveDisplayInfo(result: Result)", parameterMatchers: matchers)) + func showSearch(from view: M1, delegate: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppListViewProtocol?, DAppSearchDelegate)> where M1.OptionalMatchedType == DAppListViewProtocol, M2.MatchedType == DAppSearchDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?, DAppSearchDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListWireframeProtocol.self, method: "showSearch(from: DAppListViewProtocol?, delegate: DAppSearchDelegate)", parameterMatchers: matchers)) } - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) + func showBrowser(from view: M1, for result: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppListViewProtocol?, DAppSearchResult)> where M1.OptionalMatchedType == DAppListViewProtocol, M2.MatchedType == DAppSearchResult { + let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?, DAppSearchResult)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: result) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListWireframeProtocol.self, method: "showBrowser(from: DAppListViewProtocol?, for: DAppSearchResult)", parameterMatchers: matchers)) } - func didReceiveBlockNumber(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveBlockNumber(result: Result)", parameterMatchers: matchers)) + func showSetting(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppListViewProtocol?)> where M1.OptionalMatchedType == DAppListViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListWireframeProtocol.self, method: "showSetting(from: DAppListViewProtocol?)", parameterMatchers: matchers)) } - func didReceiveBlockDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveBlockDuration(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveLeasingPeriod(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveLeasingOffset(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveMinimumBalance(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveMinimumBalance(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveMinimumContribution(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveMinimumContribution(result: Result)", parameterMatchers: matchers)) - } - - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppListWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppListWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -11281,75 +11003,33 @@ import SoraFoundation @discardableResult - func didReceiveCrowdloan(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveCrowdloan(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveDisplayInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveDisplayInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBlockNumber(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBlockNumber(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBlockDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBlockDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveLeasingPeriod(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingPeriod(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveLeasingOffset(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingOffset(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveMinimumBalance(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMinimumBalance(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showSearch(from view: M1, delegate: M2) -> Cuckoo.__DoNotUse<(DAppListViewProtocol?, DAppSearchDelegate), Void> where M1.OptionalMatchedType == DAppListViewProtocol, M2.MatchedType == DAppSearchDelegate { + let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?, DAppSearchDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }] + return cuckoo_manager.verify("showSearch(from: DAppListViewProtocol?, delegate: DAppSearchDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveMinimumContribution(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMinimumContribution(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showBrowser(from view: M1, for result: M2) -> Cuckoo.__DoNotUse<(DAppListViewProtocol?, DAppSearchResult), Void> where M1.OptionalMatchedType == DAppListViewProtocol, M2.MatchedType == DAppSearchResult { + let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?, DAppSearchResult)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: result) { $0.1 }] + return cuckoo_manager.verify("showBrowser(from: DAppListViewProtocol?, for: DAppSearchResult)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showSetting(from view: M1) -> Cuckoo.__DoNotUse<(DAppListViewProtocol?), Void> where M1.OptionalMatchedType == DAppListViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showSetting(from: DAppListViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionSetupInteractorOutputProtocolStub: CrowdloanContributionSetupInteractorOutputProtocol { + class DAppListWireframeProtocolStub: DAppListWireframeProtocol { @@ -11357,67 +11037,221 @@ import SoraFoundation - func didReceiveCrowdloan(result: Result) { + func showSearch(from view: DAppListViewProtocol?, delegate: DAppSearchDelegate) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveDisplayInfo(result: Result) { + func showBrowser(from view: DAppListViewProtocol?, for result: DAppSearchResult) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveAccountInfo(result: Result) { + func showSetting(from view: DAppListViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveBlockNumber(result: Result) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + +import Cuckoo +@testable import novawallet + +import SubstrateSdk + + + class MockDAppOperationConfirmViewProtocol: DAppOperationConfirmViewProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = DAppOperationConfirmViewProtocol + typealias Stubbing = __StubbingProxy_DAppOperationConfirmViewProtocol + typealias Verification = __VerificationProxy_DAppOperationConfirmViewProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func didReceiveBlockDuration(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + private var __defaultImplStub: DAppOperationConfirmViewProtocol? + + func enableDefaultImplementation(_ stub: DAppOperationConfirmViewProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + - func didReceiveLeasingPeriod(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + } - func didReceiveLeasingOffset(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } + } + + + - func didReceiveMinimumBalance(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + + func didReceive(confimationViewModel: DAppOperationConfirmViewModel) { + + return cuckoo_manager.call("didReceive(confimationViewModel: DAppOperationConfirmViewModel)", + parameters: (confimationViewModel), + escapingParameters: (confimationViewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(confimationViewModel: confimationViewModel)) + } - func didReceiveMinimumContribution(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func didReceive(feeViewModel: DAppOperationFeeViewModel) { + + return cuckoo_manager.call("didReceive(feeViewModel: DAppOperationFeeViewModel)", + parameters: (feeViewModel), + escapingParameters: (feeViewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(feeViewModel: feeViewModel)) + + } + + + struct __StubbingProxy_DAppOperationConfirmViewProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") + } + + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") + } + + + func didReceive(confimationViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationConfirmViewModel)> where M1.MatchedType == DAppOperationConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewModel)>] = [wrap(matchable: confimationViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmViewProtocol.self, method: "didReceive(confimationViewModel: DAppOperationConfirmViewModel)", parameterMatchers: matchers)) + } + + func didReceive(feeViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationFeeViewModel)> where M1.MatchedType == DAppOperationFeeViewModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationFeeViewModel)>] = [wrap(matchable: feeViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmViewProtocol.self, method: "didReceive(feeViewModel: DAppOperationFeeViewModel)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_DAppOperationConfirmViewProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + + @discardableResult + func didReceive(confimationViewModel: M1) -> Cuckoo.__DoNotUse<(DAppOperationConfirmViewModel), Void> where M1.MatchedType == DAppOperationConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewModel)>] = [wrap(matchable: confimationViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(confimationViewModel: DAppOperationConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(feeViewModel: M1) -> Cuckoo.__DoNotUse<(DAppOperationFeeViewModel), Void> where M1.MatchedType == DAppOperationFeeViewModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationFeeViewModel)>] = [wrap(matchable: feeViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(feeViewModel: DAppOperationFeeViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class DAppOperationConfirmViewProtocolStub: DAppOperationConfirmViewProtocol { + + + + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + + + + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + + + - func didReceivePriceData(result: Result) { + + func didReceive(confimationViewModel: DAppOperationConfirmViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveFee(result: Result) { + func didReceive(feeViewModel: DAppOperationFeeViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -11425,19 +11259,19 @@ import SoraFoundation - class MockCrowdloanContributionSetupWireframeProtocol: CrowdloanContributionSetupWireframeProtocol, Cuckoo.ProtocolMock { + class MockDAppOperationConfirmPresenterProtocol: DAppOperationConfirmPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanContributionSetupWireframeProtocol + typealias MocksType = DAppOperationConfirmPresenterProtocol - typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupWireframeProtocol - typealias Verification = __VerificationProxy_CrowdloanContributionSetupWireframeProtocol + typealias Stubbing = __StubbingProxy_DAppOperationConfirmPresenterProtocol + typealias Verification = __VerificationProxy_DAppOperationConfirmPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanContributionSetupWireframeProtocol? + private var __defaultImplStub: DAppOperationConfirmPresenterProtocol? - func enableDefaultImplementation(_ stub: CrowdloanContributionSetupWireframeProtocol) { + func enableDefaultImplementation(_ stub: DAppOperationConfirmPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -11450,81 +11284,66 @@ import SoraFoundation - func showConfirmation(from view: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?) { - - return cuckoo_manager.call("showConfirmation(from: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?)", - parameters: (view, paraId, inputAmount, bonusService), - escapingParameters: (view, paraId, inputAmount, bonusService), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showConfirmation(from: view, paraId: paraId, inputAmount: inputAmount, bonusService: bonusService)) - - } - - - - func showAdditionalBonus(from view: CrowdloanContributionSetupViewProtocol?, for displayInfo: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?) { + func setup() { - return cuckoo_manager.call("showAdditionalBonus(from: CrowdloanContributionSetupViewProtocol?, for: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?)", - parameters: (view, displayInfo, inputAmount, delegate, existingService), - escapingParameters: (view, displayInfo, inputAmount, delegate, existingService), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showAdditionalBonus(from: view, for: displayInfo, inputAmount: inputAmount, delegate: delegate, existingService: existingService)) + defaultCall: __defaultImplStub!.setup()) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func confirm() { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("confirm()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.confirm()) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func reject() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("reject()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.reject()) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func activateTxDetails() { - return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", - parameters: (url, view, style), - escapingParameters: (url, view, style), + return cuckoo_manager.call("activateTxDetails()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) + defaultCall: __defaultImplStub!.activateTxDetails()) } - struct __StubbingProxy_CrowdloanContributionSetupWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppOperationConfirmPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -11532,34 +11351,29 @@ import SoraFoundation } - func showConfirmation(from view: M1, paraId: M2, inputAmount: M3, bonusService: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributionSetupViewProtocol?, ParaId, Decimal, CrowdloanBonusServiceProtocol?)> where M1.OptionalMatchedType == CrowdloanContributionSetupViewProtocol, M2.MatchedType == ParaId, M3.MatchedType == Decimal, M4.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewProtocol?, ParaId, Decimal, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: paraId) { $0.1 }, wrap(matchable: inputAmount) { $0.2 }, wrap(matchable: bonusService) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "showConfirmation(from: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) - } - - func showAdditionalBonus(from view: M1, for displayInfo: M2, inputAmount: M3, delegate: M4, existingService: M5) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributionSetupViewProtocol?, CrowdloanDisplayInfo, Decimal, CustomCrowdloanDelegate, CrowdloanBonusServiceProtocol?)> where M1.OptionalMatchedType == CrowdloanContributionSetupViewProtocol, M2.MatchedType == CrowdloanDisplayInfo, M3.MatchedType == Decimal, M4.MatchedType == CustomCrowdloanDelegate, M5.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewProtocol?, CrowdloanDisplayInfo, Decimal, CustomCrowdloanDelegate, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: displayInfo) { $0.1 }, wrap(matchable: inputAmount) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: existingService) { $0.4 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "showAdditionalBonus(from: CrowdloanContributionSetupViewProtocol?, for: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func reject() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmPresenterProtocol.self, method: "reject()", parameterMatchers: matchers)) } - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) + func activateTxDetails() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmPresenterProtocol.self, method: "activateTxDetails()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanContributionSetupWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppOperationConfirmPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -11574,39 +11388,33 @@ import SoraFoundation @discardableResult - func showConfirmation(from view: M1, paraId: M2, inputAmount: M3, bonusService: M4) -> Cuckoo.__DoNotUse<(CrowdloanContributionSetupViewProtocol?, ParaId, Decimal, CrowdloanBonusServiceProtocol?), Void> where M1.OptionalMatchedType == CrowdloanContributionSetupViewProtocol, M2.MatchedType == ParaId, M3.MatchedType == Decimal, M4.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewProtocol?, ParaId, Decimal, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: paraId) { $0.1 }, wrap(matchable: inputAmount) { $0.2 }, wrap(matchable: bonusService) { $0.3 }] - return cuckoo_manager.verify("showConfirmation(from: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showAdditionalBonus(from view: M1, for displayInfo: M2, inputAmount: M3, delegate: M4, existingService: M5) -> Cuckoo.__DoNotUse<(CrowdloanContributionSetupViewProtocol?, CrowdloanDisplayInfo, Decimal, CustomCrowdloanDelegate, CrowdloanBonusServiceProtocol?), Void> where M1.OptionalMatchedType == CrowdloanContributionSetupViewProtocol, M2.MatchedType == CrowdloanDisplayInfo, M3.MatchedType == Decimal, M4.MatchedType == CustomCrowdloanDelegate, M5.OptionalMatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewProtocol?, CrowdloanDisplayInfo, Decimal, CustomCrowdloanDelegate, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: displayInfo) { $0.1 }, wrap(matchable: inputAmount) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: existingService) { $0.4 }] - return cuckoo_manager.verify("showAdditionalBonus(from: CrowdloanContributionSetupViewProtocol?, for: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func confirm() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reject() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("reject()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func activateTxDetails() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("activateTxDetails()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanContributionSetupWireframeProtocolStub: CrowdloanContributionSetupWireframeProtocol { + class DAppOperationConfirmPresenterProtocolStub: DAppOperationConfirmPresenterProtocol { @@ -11614,229 +11422,132 @@ import SoraFoundation - func showConfirmation(from view: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showAdditionalBonus(from view: CrowdloanContributionSetupViewProtocol?, for displayInfo: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func confirm() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func reject() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func activateTxDetails() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import SoraFoundation - - class MockCrowdloanListViewProtocol: CrowdloanListViewProtocol, Cuckoo.ProtocolMock { + class MockDAppOperationConfirmInteractorInputProtocol: DAppOperationConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanListViewProtocol + typealias MocksType = DAppOperationConfirmInteractorInputProtocol - typealias Stubbing = __StubbingProxy_CrowdloanListViewProtocol - typealias Verification = __VerificationProxy_CrowdloanListViewProtocol + typealias Stubbing = __StubbingProxy_DAppOperationConfirmInteractorInputProtocol + typealias Verification = __VerificationProxy_DAppOperationConfirmInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanListViewProtocol? + private var __defaultImplStub: DAppOperationConfirmInteractorInputProtocol? - func enableDefaultImplementation(_ stub: CrowdloanListViewProtocol) { + func enableDefaultImplementation(_ stub: DAppOperationConfirmInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - - - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } - - } - - func didReceive(walletSwitchViewModel: WalletSwitchViewModel) { + func setup() { - return cuckoo_manager.call("didReceive(walletSwitchViewModel: WalletSwitchViewModel)", - parameters: (walletSwitchViewModel), - escapingParameters: (walletSwitchViewModel), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(walletSwitchViewModel: walletSwitchViewModel)) + defaultCall: __defaultImplStub!.setup()) } - func didReceive(chainInfo: CrowdloansChainViewModel) { + func estimateFee() { - return cuckoo_manager.call("didReceive(chainInfo: CrowdloansChainViewModel)", - parameters: (chainInfo), - escapingParameters: (chainInfo), + return cuckoo_manager.call("estimateFee()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(chainInfo: chainInfo)) + defaultCall: __defaultImplStub!.estimateFee()) } - func didReceive(listState: CrowdloanListState) { - - return cuckoo_manager.call("didReceive(listState: CrowdloanListState)", - parameters: (listState), - escapingParameters: (listState), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(listState: listState)) - - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) - - } - - - - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func confirm() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("confirm()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.confirm()) } - func didStartLoading() { + func reject() { - return cuckoo_manager.call("didStartLoading()", + return cuckoo_manager.call("reject()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStartLoading()) + defaultCall: __defaultImplStub!.reject()) } - func didStopLoading() { + func prepareTxDetails() { - return cuckoo_manager.call("didStopLoading()", + return cuckoo_manager.call("prepareTxDetails()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopLoading()) + defaultCall: __defaultImplStub!.prepareTxDetails()) } - struct __StubbingProxy_CrowdloanListViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppOperationConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -11844,64 +11555,34 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") - } - - - func didReceive(walletSwitchViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(WalletSwitchViewModel)> where M1.MatchedType == WalletSwitchViewModel { - let matchers: [Cuckoo.ParameterMatcher<(WalletSwitchViewModel)>] = [wrap(matchable: walletSwitchViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListViewProtocol.self, method: "didReceive(walletSwitchViewModel: WalletSwitchViewModel)", parameterMatchers: matchers)) - } - - func didReceive(chainInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloansChainViewModel)> where M1.MatchedType == CrowdloansChainViewModel { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloansChainViewModel)>] = [wrap(matchable: chainInfo) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListViewProtocol.self, method: "didReceive(chainInfo: CrowdloansChainViewModel)", parameterMatchers: matchers)) - } - - func didReceive(listState: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanListState)> where M1.MatchedType == CrowdloanListState { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanListState)>] = [wrap(matchable: listState) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListViewProtocol.self, method: "didReceive(listState: CrowdloanListState)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListViewProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListViewProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "confirm()", parameterMatchers: matchers)) } - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func reject() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "reject()", parameterMatchers: matchers)) } - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func prepareTxDetails() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "prepareTxDetails()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanListViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppOperationConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -11913,110 +11594,42 @@ import SoraFoundation } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceive(walletSwitchViewModel: M1) -> Cuckoo.__DoNotUse<(WalletSwitchViewModel), Void> where M1.MatchedType == WalletSwitchViewModel { - let matchers: [Cuckoo.ParameterMatcher<(WalletSwitchViewModel)>] = [wrap(matchable: walletSwitchViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(walletSwitchViewModel: WalletSwitchViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(chainInfo: M1) -> Cuckoo.__DoNotUse<(CrowdloansChainViewModel), Void> where M1.MatchedType == CrowdloansChainViewModel { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloansChainViewModel)>] = [wrap(matchable: chainInfo) { $0 }] - return cuckoo_manager.verify("didReceive(chainInfo: CrowdloansChainViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(listState: M1) -> Cuckoo.__DoNotUse<(CrowdloanListState), Void> where M1.MatchedType == CrowdloanListState { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanListState)>] = [wrap(matchable: listState) { $0 }] - return cuckoo_manager.verify("didReceive(listState: CrowdloanListState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func confirm() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + func reject() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("reject()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + func prepareTxDetails() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("prepareTxDetails()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanListViewProtocolStub: CrowdloanListViewProtocol { - - - - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - - - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } - - - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } + class DAppOperationConfirmInteractorInputProtocolStub: DAppOperationConfirmInteractorInputProtocol { @@ -12024,43 +11637,31 @@ import SoraFoundation - func didReceive(walletSwitchViewModel: WalletSwitchViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(chainInfo: CrowdloansChainViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(listState: CrowdloanListState) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func estimateFee() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func confirm() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoading() { + func reject() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStopLoading() { + func prepareTxDetails() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -12068,19 +11669,19 @@ import SoraFoundation - class MockCrowdloanListPresenterProtocol: CrowdloanListPresenterProtocol, Cuckoo.ProtocolMock { + class MockDAppOperationConfirmInteractorOutputProtocol: DAppOperationConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanListPresenterProtocol + typealias MocksType = DAppOperationConfirmInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_CrowdloanListPresenterProtocol - typealias Verification = __VerificationProxy_CrowdloanListPresenterProtocol + typealias Stubbing = __StubbingProxy_DAppOperationConfirmInteractorOutputProtocol + typealias Verification = __VerificationProxy_DAppOperationConfirmInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanListPresenterProtocol? + private var __defaultImplStub: DAppOperationConfirmInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: CrowdloanListPresenterProtocol) { + func enableDefaultImplementation(_ stub: DAppOperationConfirmInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -12093,126 +11694,81 @@ import SoraFoundation - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - - } - - - - func refresh(shouldReset: Bool) { - - return cuckoo_manager.call("refresh(shouldReset: Bool)", - parameters: (shouldReset), - escapingParameters: (shouldReset), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.refresh(shouldReset: shouldReset)) - - } - - - - func selectCrowdloan(_ paraId: ParaId) { - - return cuckoo_manager.call("selectCrowdloan(_: ParaId)", - parameters: (paraId), - escapingParameters: (paraId), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.selectCrowdloan(paraId)) - - } - - - - func becomeOnline() { + func didReceive(modelResult: Result) { - return cuckoo_manager.call("becomeOnline()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(modelResult: Result)", + parameters: (modelResult), + escapingParameters: (modelResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.becomeOnline()) + defaultCall: __defaultImplStub!.didReceive(modelResult: modelResult)) } - func putOffline() { + func didReceive(feeResult: Result) { - return cuckoo_manager.call("putOffline()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(feeResult: Result)", + parameters: (feeResult), + escapingParameters: (feeResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.putOffline()) + defaultCall: __defaultImplStub!.didReceive(feeResult: feeResult)) } - func selectChain() { + func didReceive(priceResult: Result) { - return cuckoo_manager.call("selectChain()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(priceResult: Result)", + parameters: (priceResult), + escapingParameters: (priceResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectChain()) + defaultCall: __defaultImplStub!.didReceive(priceResult: priceResult)) } - func handleYourContributions() { + func didReceive(responseResult: Result, for request: DAppOperationRequest) { - return cuckoo_manager.call("handleYourContributions()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(responseResult: Result, for: DAppOperationRequest)", + parameters: (responseResult, request), + escapingParameters: (responseResult, request), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.handleYourContributions()) + defaultCall: __defaultImplStub!.didReceive(responseResult: responseResult, for: request)) } - func handleWalletSwitch() { + func didReceive(txDetailsResult: Result) { - return cuckoo_manager.call("handleWalletSwitch()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(txDetailsResult: Result)", + parameters: (txDetailsResult), + escapingParameters: (txDetailsResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.handleWalletSwitch()) + defaultCall: __defaultImplStub!.didReceive(txDetailsResult: txDetailsResult)) } - struct __StubbingProxy_CrowdloanListPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppOperationConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -12220,49 +11776,34 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func refresh(shouldReset: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: shouldReset) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "refresh(shouldReset: Bool)", parameterMatchers: matchers)) - } - - func selectCrowdloan(_ paraId: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ParaId)> where M1.MatchedType == ParaId { - let matchers: [Cuckoo.ParameterMatcher<(ParaId)>] = [wrap(matchable: paraId) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "selectCrowdloan(_: ParaId)", parameterMatchers: matchers)) - } - - func becomeOnline() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "becomeOnline()", parameterMatchers: matchers)) + func didReceive(modelResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: modelResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(modelResult: Result)", parameterMatchers: matchers)) } - func putOffline() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "putOffline()", parameterMatchers: matchers)) + func didReceive(feeResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: feeResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(feeResult: Result)", parameterMatchers: matchers)) } - func selectChain() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "selectChain()", parameterMatchers: matchers)) + func didReceive(priceResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(priceResult: Result)", parameterMatchers: matchers)) } - func handleYourContributions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "handleYourContributions()", parameterMatchers: matchers)) + func didReceive(responseResult: M1, for request: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Result, DAppOperationRequest)> where M1.MatchedType == Result, M2.MatchedType == DAppOperationRequest { + let matchers: [Cuckoo.ParameterMatcher<(Result, DAppOperationRequest)>] = [wrap(matchable: responseResult) { $0.0 }, wrap(matchable: request) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(responseResult: Result, for: DAppOperationRequest)", parameterMatchers: matchers)) } - func handleWalletSwitch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "handleWalletSwitch()", parameterMatchers: matchers)) + func didReceive(txDetailsResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: txDetailsResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(txDetailsResult: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanListPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppOperationConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -12277,57 +11818,39 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func refresh(shouldReset: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: shouldReset) { $0 }] - return cuckoo_manager.verify("refresh(shouldReset: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func selectCrowdloan(_ paraId: M1) -> Cuckoo.__DoNotUse<(ParaId), Void> where M1.MatchedType == ParaId { - let matchers: [Cuckoo.ParameterMatcher<(ParaId)>] = [wrap(matchable: paraId) { $0 }] - return cuckoo_manager.verify("selectCrowdloan(_: ParaId)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func becomeOnline() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("becomeOnline()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(modelResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: modelResult) { $0 }] + return cuckoo_manager.verify("didReceive(modelResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func putOffline() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("putOffline()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(feeResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: feeResult) { $0 }] + return cuckoo_manager.verify("didReceive(feeResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectChain() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectChain()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(priceResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] + return cuckoo_manager.verify("didReceive(priceResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func handleYourContributions() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handleYourContributions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(responseResult: M1, for request: M2) -> Cuckoo.__DoNotUse<(Result, DAppOperationRequest), Void> where M1.MatchedType == Result, M2.MatchedType == DAppOperationRequest { + let matchers: [Cuckoo.ParameterMatcher<(Result, DAppOperationRequest)>] = [wrap(matchable: responseResult) { $0.0 }, wrap(matchable: request) { $0.1 }] + return cuckoo_manager.verify("didReceive(responseResult: Result, for: DAppOperationRequest)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func handleWalletSwitch() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handleWalletSwitch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(txDetailsResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: txDetailsResult) { $0 }] + return cuckoo_manager.verify("didReceive(txDetailsResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanListPresenterProtocolStub: CrowdloanListPresenterProtocol { + class DAppOperationConfirmInteractorOutputProtocolStub: DAppOperationConfirmInteractorOutputProtocol { @@ -12335,49 +11858,31 @@ import SoraFoundation - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func refresh(shouldReset: Bool) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func selectCrowdloan(_ paraId: ParaId) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func becomeOnline() { + func didReceive(modelResult: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func putOffline() { + func didReceive(feeResult: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectChain() { + func didReceive(priceResult: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func handleYourContributions() { + func didReceive(responseResult: Result, for request: DAppOperationRequest) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func handleWalletSwitch() { + func didReceive(txDetailsResult: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -12385,19 +11890,19 @@ import SoraFoundation - class MockCrowdloanListInteractorInputProtocol: CrowdloanListInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockDAppOperationConfirmWireframeProtocol: DAppOperationConfirmWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanListInteractorInputProtocol + typealias MocksType = DAppOperationConfirmWireframeProtocol - typealias Stubbing = __StubbingProxy_CrowdloanListInteractorInputProtocol - typealias Verification = __VerificationProxy_CrowdloanListInteractorInputProtocol + typealias Stubbing = __StubbingProxy_DAppOperationConfirmWireframeProtocol + typealias Verification = __VerificationProxy_DAppOperationConfirmWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanListInteractorInputProtocol? + private var __defaultImplStub: DAppOperationConfirmWireframeProtocol? - func enableDefaultImplementation(_ stub: CrowdloanListInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: DAppOperationConfirmWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -12410,81 +11915,66 @@ import SoraFoundation - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - - } - - - - func refresh() { + func close(view: DAppOperationConfirmViewProtocol?) { - return cuckoo_manager.call("refresh()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("close(view: DAppOperationConfirmViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.refresh()) + defaultCall: __defaultImplStub!.close(view: view)) } - func saveSelected(chainModel: ChainModel) { + func showTxDetails(from view: DAppOperationConfirmViewProtocol?, json: JSON) { - return cuckoo_manager.call("saveSelected(chainModel: ChainModel)", - parameters: (chainModel), - escapingParameters: (chainModel), + return cuckoo_manager.call("showTxDetails(from: DAppOperationConfirmViewProtocol?, json: JSON)", + parameters: (view, json), + escapingParameters: (view, json), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.saveSelected(chainModel: chainModel)) + defaultCall: __defaultImplStub!.showTxDetails(from: view, json: json)) } - func becomeOnline() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("becomeOnline()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.becomeOnline()) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - func putOffline() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("putOffline()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.putOffline()) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_CrowdloanListInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppOperationConfirmWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -12492,34 +11982,29 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationConfirmViewProtocol?)> where M1.OptionalMatchedType == DAppOperationConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmWireframeProtocol.self, method: "close(view: DAppOperationConfirmViewProtocol?)", parameterMatchers: matchers)) } - func refresh() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "refresh()", parameterMatchers: matchers)) + func showTxDetails(from view: M1, json: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationConfirmViewProtocol?, JSON)> where M1.OptionalMatchedType == DAppOperationConfirmViewProtocol, M2.MatchedType == JSON { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewProtocol?, JSON)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: json) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmWireframeProtocol.self, method: "showTxDetails(from: DAppOperationConfirmViewProtocol?, json: JSON)", parameterMatchers: matchers)) } - func saveSelected(chainModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainModel)> where M1.MatchedType == ChainModel { - let matchers: [Cuckoo.ParameterMatcher<(ChainModel)>] = [wrap(matchable: chainModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "saveSelected(chainModel: ChainModel)", parameterMatchers: matchers)) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func becomeOnline() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "becomeOnline()", parameterMatchers: matchers)) - } - - func putOffline() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "putOffline()", parameterMatchers: matchers)) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanListInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppOperationConfirmWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -12534,39 +12019,33 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func refresh() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("refresh()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func close(view: M1) -> Cuckoo.__DoNotUse<(DAppOperationConfirmViewProtocol?), Void> where M1.OptionalMatchedType == DAppOperationConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(view: DAppOperationConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func saveSelected(chainModel: M1) -> Cuckoo.__DoNotUse<(ChainModel), Void> where M1.MatchedType == ChainModel { - let matchers: [Cuckoo.ParameterMatcher<(ChainModel)>] = [wrap(matchable: chainModel) { $0 }] - return cuckoo_manager.verify("saveSelected(chainModel: ChainModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showTxDetails(from view: M1, json: M2) -> Cuckoo.__DoNotUse<(DAppOperationConfirmViewProtocol?, JSON), Void> where M1.OptionalMatchedType == DAppOperationConfirmViewProtocol, M2.MatchedType == JSON { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewProtocol?, JSON)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: json) { $0.1 }] + return cuckoo_manager.verify("showTxDetails(from: DAppOperationConfirmViewProtocol?, json: JSON)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func becomeOnline() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("becomeOnline()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func putOffline() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("putOffline()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanListInteractorInputProtocolStub: CrowdloanListInteractorInputProtocol { + class DAppOperationConfirmWireframeProtocolStub: DAppOperationConfirmWireframeProtocol { @@ -12574,31 +12053,25 @@ import SoraFoundation - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func refresh() { + func close(view: DAppOperationConfirmViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func saveSelected(chainModel: ChainModel) { + func showTxDetails(from view: DAppOperationConfirmViewProtocol?, json: JSON) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func becomeOnline() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func putOffline() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -12606,19 +12079,19 @@ import SoraFoundation - class MockCrowdloanListInteractorOutputProtocol: CrowdloanListInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockDAppOperationConfirmDelegate: DAppOperationConfirmDelegate, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanListInteractorOutputProtocol + typealias MocksType = DAppOperationConfirmDelegate - typealias Stubbing = __StubbingProxy_CrowdloanListInteractorOutputProtocol - typealias Verification = __VerificationProxy_CrowdloanListInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_DAppOperationConfirmDelegate + typealias Verification = __VerificationProxy_DAppOperationConfirmDelegate let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanListInteractorOutputProtocol? + private var __defaultImplStub: DAppOperationConfirmDelegate? - func enableDefaultImplementation(_ stub: CrowdloanListInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: DAppOperationConfirmDelegate) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -12631,201 +12104,370 @@ import SoraFoundation - func didReceiveCrowdloans(result: Result<[Crowdloan], Error>) { + func didReceiveConfirmationResponse(_ response: DAppOperationResponse, for request: DAppOperationRequest) { - return cuckoo_manager.call("didReceiveCrowdloans(result: Result<[Crowdloan], Error>)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveConfirmationResponse(_: DAppOperationResponse, for: DAppOperationRequest)", + parameters: (response, request), + escapingParameters: (response, request), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveCrowdloans(result: result)) + defaultCall: __defaultImplStub!.didReceiveConfirmationResponse(response, for: request)) } + + struct __StubbingProxy_DAppOperationConfirmDelegate: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func didReceiveConfirmationResponse(_ response: M1, for request: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationResponse, DAppOperationRequest)> where M1.MatchedType == DAppOperationResponse, M2.MatchedType == DAppOperationRequest { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationResponse, DAppOperationRequest)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: request) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmDelegate.self, method: "didReceiveConfirmationResponse(_: DAppOperationResponse, for: DAppOperationRequest)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_DAppOperationConfirmDelegate: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func didReceiveConfirmationResponse(_ response: M1, for request: M2) -> Cuckoo.__DoNotUse<(DAppOperationResponse, DAppOperationRequest), Void> where M1.MatchedType == DAppOperationResponse, M2.MatchedType == DAppOperationRequest { + let matchers: [Cuckoo.ParameterMatcher<(DAppOperationResponse, DAppOperationRequest)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: request) { $0.1 }] + return cuckoo_manager.verify("didReceiveConfirmationResponse(_: DAppOperationResponse, for: DAppOperationRequest)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class DAppOperationConfirmDelegateStub: DAppOperationConfirmDelegate { + - func didReceiveDisplayInfo(result: Result) { - - return cuckoo_manager.call("didReceiveDisplayInfo(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveDisplayInfo(result: result)) - + + + + + func didReceiveConfirmationResponse(_ response: DAppOperationResponse, for request: DAppOperationRequest) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + +import Cuckoo +@testable import novawallet + +import RobinHood + + + class MockDAppSearchViewProtocol: DAppSearchViewProtocol, Cuckoo.ProtocolMock { + typealias MocksType = DAppSearchViewProtocol - func didReceiveBlockNumber(result: Result) { - - return cuckoo_manager.call("didReceiveBlockNumber(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBlockNumber(result: result)) - + typealias Stubbing = __StubbingProxy_DAppSearchViewProtocol + typealias Verification = __VerificationProxy_DAppSearchViewProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: DAppSearchViewProtocol? + + func enableDefaultImplementation(_ stub: DAppSearchViewProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + - func didReceiveBlockDuration(result: Result) { - - return cuckoo_manager.call("didReceiveBlockDuration(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBlockDuration(result: result)) + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } } - func didReceiveLeasingPeriod(result: Result) { - - return cuckoo_manager.call("didReceiveLeasingPeriod(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(result: result)) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } + + + - func didReceiveLeasingOffset(result: Result) { + + func didReceive(initialQuery: String) { - return cuckoo_manager.call("didReceiveLeasingOffset(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceive(initialQuery: String)", + parameters: (initialQuery), + escapingParameters: (initialQuery), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveLeasingOffset(result: result)) + defaultCall: __defaultImplStub!.didReceive(initialQuery: initialQuery)) } - func didReceiveContributions(result: Result) { + func didReceiveDApp(viewModels: [DAppViewModel]) { - return cuckoo_manager.call("didReceiveContributions(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveDApp(viewModels: [DAppViewModel])", + parameters: (viewModels), + escapingParameters: (viewModels), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveContributions(result: result)) + defaultCall: __defaultImplStub!.didReceiveDApp(viewModels: viewModels)) } + + struct __StubbingProxy_DAppSearchViewProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") + } + + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") + } + + + func didReceive(initialQuery: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: initialQuery) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchViewProtocol.self, method: "didReceive(initialQuery: String)", parameterMatchers: matchers)) + } + + func didReceiveDApp(viewModels: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([DAppViewModel])> where M1.MatchedType == [DAppViewModel] { + let matchers: [Cuckoo.ParameterMatcher<([DAppViewModel])>] = [wrap(matchable: viewModels) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchViewProtocol.self, method: "didReceiveDApp(viewModels: [DAppViewModel])", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_DAppSearchViewProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + + @discardableResult + func didReceive(initialQuery: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: initialQuery) { $0 }] + return cuckoo_manager.verify("didReceive(initialQuery: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveDApp(viewModels: M1) -> Cuckoo.__DoNotUse<([DAppViewModel]), Void> where M1.MatchedType == [DAppViewModel] { + let matchers: [Cuckoo.ParameterMatcher<([DAppViewModel])>] = [wrap(matchable: viewModels) { $0 }] + return cuckoo_manager.verify("didReceiveDApp(viewModels: [DAppViewModel])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class DAppSearchViewProtocolStub: DAppSearchViewProtocol { + - func didReceiveExternalContributions(result: Result<[ExternalContribution], Error>) { + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } - return cuckoo_manager.call("didReceiveExternalContributions(result: Result<[ExternalContribution], Error>)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveExternalContributions(result: result)) + } + + + + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } } + + + + - func didReceiveLeaseInfo(result: Result) { + func didReceive(initialQuery: String) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveDApp(viewModels: [DAppViewModel]) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + + + class MockDAppSearchPresenterProtocol: DAppSearchPresenterProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = DAppSearchPresenterProtocol + + typealias Stubbing = __StubbingProxy_DAppSearchPresenterProtocol + typealias Verification = __VerificationProxy_DAppSearchPresenterProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: DAppSearchPresenterProtocol? + + func enableDefaultImplementation(_ stub: DAppSearchPresenterProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + + + + + + + + + func setup() { - return cuckoo_manager.call("didReceiveLeaseInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveLeaseInfo(result: result)) + defaultCall: __defaultImplStub!.setup()) } - func didReceiveSelectedChain(result: Result) { + func updateSearch(query: String) { - return cuckoo_manager.call("didReceiveSelectedChain(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("updateSearch(query: String)", + parameters: (query), + escapingParameters: (query), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveSelectedChain(result: result)) + defaultCall: __defaultImplStub!.updateSearch(query: query)) } - func didReceiveAccountInfo(result: Result) { + func selectDApp(viewModel: DAppViewModel) { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("selectDApp(viewModel: DAppViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.selectDApp(viewModel: viewModel)) } - func didReceive(wallet: MetaAccountModel) { + func selectSearchQuery() { - return cuckoo_manager.call("didReceive(wallet: MetaAccountModel)", - parameters: (wallet), - escapingParameters: (wallet), + return cuckoo_manager.call("selectSearchQuery()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(wallet: wallet)) + defaultCall: __defaultImplStub!.selectSearchQuery()) } - func didReceivePriceData(result: Result?) { + func cancel() { - return cuckoo_manager.call("didReceivePriceData(result: Result?)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("cancel()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + defaultCall: __defaultImplStub!.cancel()) } - struct __StubbingProxy_CrowdloanListInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppSearchPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -12833,74 +12475,34 @@ import SoraFoundation } - func didReceiveCrowdloans(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[Crowdloan], Error>)> where M1.MatchedType == Result<[Crowdloan], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[Crowdloan], Error>)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveCrowdloans(result: Result<[Crowdloan], Error>)", parameterMatchers: matchers)) - } - - func didReceiveDisplayInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveDisplayInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveBlockNumber(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveBlockNumber(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveBlockDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveBlockDuration(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveLeasingPeriod(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveLeasingOffset(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveContributions(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveContributions(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveExternalContributions(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[ExternalContribution], Error>)> where M1.MatchedType == Result<[ExternalContribution], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[ExternalContribution], Error>)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveExternalContributions(result: Result<[ExternalContribution], Error>)", parameterMatchers: matchers)) - } - - func didReceiveLeaseInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveLeaseInfo(result: Result)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func didReceiveSelectedChain(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveSelectedChain(result: Result)", parameterMatchers: matchers)) + func updateSearch(query: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: query) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "updateSearch(query: String)", parameterMatchers: matchers)) } - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) + func selectDApp(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppViewModel)> where M1.MatchedType == DAppViewModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "selectDApp(viewModel: DAppViewModel)", parameterMatchers: matchers)) } - func didReceive(wallet: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(MetaAccountModel)> where M1.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceive(wallet: MetaAccountModel)", parameterMatchers: matchers)) + func selectSearchQuery() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "selectSearchQuery()", parameterMatchers: matchers)) } - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result?)> where M1.OptionalMatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result?)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result?)", parameterMatchers: matchers)) + func cancel() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "cancel()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanListInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppSearchPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -12915,87 +12517,39 @@ import SoraFoundation @discardableResult - func didReceiveCrowdloans(result: M1) -> Cuckoo.__DoNotUse<(Result<[Crowdloan], Error>), Void> where M1.MatchedType == Result<[Crowdloan], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[Crowdloan], Error>)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveCrowdloans(result: Result<[Crowdloan], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveDisplayInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveDisplayInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func updateSearch(query: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: query) { $0 }] + return cuckoo_manager.verify("updateSearch(query: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveBlockNumber(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBlockNumber(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectDApp(viewModel: M1) -> Cuckoo.__DoNotUse<(DAppViewModel), Void> where M1.MatchedType == DAppViewModel { + let matchers: [Cuckoo.ParameterMatcher<(DAppViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("selectDApp(viewModel: DAppViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveBlockDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBlockDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveLeasingPeriod(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingPeriod(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveLeasingOffset(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingOffset(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveContributions(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveContributions(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveExternalContributions(result: M1) -> Cuckoo.__DoNotUse<(Result<[ExternalContribution], Error>), Void> where M1.MatchedType == Result<[ExternalContribution], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[ExternalContribution], Error>)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveExternalContributions(result: Result<[ExternalContribution], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveLeaseInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLeaseInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveSelectedChain(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveSelectedChain(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(wallet: M1) -> Cuckoo.__DoNotUse<(MetaAccountModel), Void> where M1.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] - return cuckoo_manager.verify("didReceive(wallet: MetaAccountModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectSearchQuery() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectSearchQuery()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result?), Void> where M1.OptionalMatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result?)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func cancel() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("cancel()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanListInteractorOutputProtocolStub: CrowdloanListInteractorOutputProtocol { + class DAppSearchPresenterProtocolStub: DAppSearchPresenterProtocol { @@ -13003,79 +12557,31 @@ import SoraFoundation - func didReceiveCrowdloans(result: Result<[Crowdloan], Error>) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveDisplayInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveBlockNumber(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveBlockDuration(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveLeasingPeriod(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveLeasingOffset(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveContributions(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveExternalContributions(result: Result<[ExternalContribution], Error>) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveLeaseInfo(result: Result) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveSelectedChain(result: Result) { + func updateSearch(query: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveAccountInfo(result: Result) { + func selectDApp(viewModel: DAppViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(wallet: MetaAccountModel) { + func selectSearchQuery() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceivePriceData(result: Result?) { + func cancel() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -13083,19 +12589,19 @@ import SoraFoundation - class MockCrowdloanListWireframeProtocol: CrowdloanListWireframeProtocol, Cuckoo.ProtocolMock { + class MockDAppSearchInteractorInputProtocol: DAppSearchInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanListWireframeProtocol + typealias MocksType = DAppSearchInteractorInputProtocol - typealias Stubbing = __StubbingProxy_CrowdloanListWireframeProtocol - typealias Verification = __VerificationProxy_CrowdloanListWireframeProtocol + typealias Stubbing = __StubbingProxy_DAppSearchInteractorInputProtocol + typealias Verification = __VerificationProxy_DAppSearchInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanListWireframeProtocol? + private var __defaultImplStub: DAppSearchInteractorInputProtocol? - func enableDefaultImplementation(_ stub: CrowdloanListWireframeProtocol) { + func enableDefaultImplementation(_ stub: DAppSearchInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -13108,96 +12614,21 @@ import SoraFoundation - func presentContributionSetup(from view: CrowdloanListViewProtocol?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?) { - - return cuckoo_manager.call("presentContributionSetup(from: CrowdloanListViewProtocol?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?)", - parameters: (view, crowdloan, displayInfo), - escapingParameters: (view, crowdloan, displayInfo), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.presentContributionSetup(from: view, crowdloan: crowdloan, displayInfo: displayInfo)) - - } - - - - func showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from: ControllerBackedProtocol?)", - parameters: (crowdloans, viewInfo, chainAsset, view), - escapingParameters: (crowdloans, viewInfo, chainAsset, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showYourContributions(crowdloans: crowdloans, viewInfo: viewInfo, chainAsset: chainAsset, from: view)) - - } - - - - func selectChain(from view: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?) { - - return cuckoo_manager.call("selectChain(from: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?)", - parameters: (view, delegate, selectedChainAssetId), - escapingParameters: (view, delegate, selectedChainAssetId), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.selectChain(from: view, delegate: delegate, selectedChainAssetId: selectedChainAssetId)) - - } - - - - func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) { - - return cuckoo_manager.call("showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", - parameters: (view, wallet), - escapingParameters: (view, wallet), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showWalletDetails(from: view, wallet: wallet)) - - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) - - } - - - - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func setup() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.setup()) } - struct __StubbingProxy_CrowdloanListWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppSearchInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -13205,39 +12636,14 @@ import SoraFoundation } - func presentContributionSetup(from view: M1, crowdloan: M2, displayInfo: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanListViewProtocol?, Crowdloan, CrowdloanDisplayInfo?)> where M1.OptionalMatchedType == CrowdloanListViewProtocol, M2.MatchedType == Crowdloan, M3.OptionalMatchedType == CrowdloanDisplayInfo { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanListViewProtocol?, Crowdloan, CrowdloanDisplayInfo?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: crowdloan) { $0.1 }, wrap(matchable: displayInfo) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "presentContributionSetup(from: CrowdloanListViewProtocol?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?)", parameterMatchers: matchers)) - } - - func showYourContributions(crowdloans: M1, viewInfo: M2, chainAsset: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<([Crowdloan], CrowdloansViewInfo, ChainAssetDisplayInfo, ControllerBackedProtocol?)> where M1.MatchedType == [Crowdloan], M2.MatchedType == CrowdloansViewInfo, M3.MatchedType == ChainAssetDisplayInfo, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<([Crowdloan], CrowdloansViewInfo, ChainAssetDisplayInfo, ControllerBackedProtocol?)>] = [wrap(matchable: crowdloans) { $0.0 }, wrap(matchable: viewInfo) { $0.1 }, wrap(matchable: chainAsset) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func selectChain(from view: M1, delegate: M2, selectedChainAssetId: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, AssetSelectionDelegate, ChainAssetId?)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AssetSelectionDelegate, M3.OptionalMatchedType == ChainAssetId { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AssetSelectionDelegate, ChainAssetId?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }, wrap(matchable: selectedChainAssetId) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "selectChain(from: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?)", parameterMatchers: matchers)) - } - - func showWalletDetails(from view: M1, wallet: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, MetaAccountModel)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaAccountModel)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: wallet) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", parameterMatchers: matchers)) - } - - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanListWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppSearchInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -13252,45 +12658,15 @@ import SoraFoundation @discardableResult - func presentContributionSetup(from view: M1, crowdloan: M2, displayInfo: M3) -> Cuckoo.__DoNotUse<(CrowdloanListViewProtocol?, Crowdloan, CrowdloanDisplayInfo?), Void> where M1.OptionalMatchedType == CrowdloanListViewProtocol, M2.MatchedType == Crowdloan, M3.OptionalMatchedType == CrowdloanDisplayInfo { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanListViewProtocol?, Crowdloan, CrowdloanDisplayInfo?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: crowdloan) { $0.1 }, wrap(matchable: displayInfo) { $0.2 }] - return cuckoo_manager.verify("presentContributionSetup(from: CrowdloanListViewProtocol?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showYourContributions(crowdloans: M1, viewInfo: M2, chainAsset: M3, from view: M4) -> Cuckoo.__DoNotUse<([Crowdloan], CrowdloansViewInfo, ChainAssetDisplayInfo, ControllerBackedProtocol?), Void> where M1.MatchedType == [Crowdloan], M2.MatchedType == CrowdloansViewInfo, M3.MatchedType == ChainAssetDisplayInfo, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<([Crowdloan], CrowdloansViewInfo, ChainAssetDisplayInfo, ControllerBackedProtocol?)>] = [wrap(matchable: crowdloans) { $0.0 }, wrap(matchable: viewInfo) { $0.1 }, wrap(matchable: chainAsset) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func selectChain(from view: M1, delegate: M2, selectedChainAssetId: M3) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, AssetSelectionDelegate, ChainAssetId?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AssetSelectionDelegate, M3.OptionalMatchedType == ChainAssetId { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AssetSelectionDelegate, ChainAssetId?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }, wrap(matchable: selectedChainAssetId) { $0.2 }] - return cuckoo_manager.verify("selectChain(from: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showWalletDetails(from view: M1, wallet: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, MetaAccountModel), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaAccountModel)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: wallet) { $0.1 }] - return cuckoo_manager.verify("showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanListWireframeProtocolStub: CrowdloanListWireframeProtocol { + class DAppSearchInteractorInputProtocolStub: DAppSearchInteractorInputProtocol { @@ -13298,133 +12674,69 @@ import SoraFoundation - func presentContributionSetup(from view: CrowdloanListViewProtocol?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func selectChain(from view: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import Foundation -import SoraFoundation - - class MockCrowdloanYourContributionsViewProtocol: CrowdloanYourContributionsViewProtocol, Cuckoo.ProtocolMock { + class MockDAppSearchInteractorOutputProtocol: DAppSearchInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanYourContributionsViewProtocol + typealias MocksType = DAppSearchInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsViewProtocol - typealias Verification = __VerificationProxy_CrowdloanYourContributionsViewProtocol + typealias Stubbing = __StubbingProxy_DAppSearchInteractorOutputProtocol + typealias Verification = __VerificationProxy_DAppSearchInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanYourContributionsViewProtocol? + private var __defaultImplStub: DAppSearchInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: CrowdloanYourContributionsViewProtocol) { + func enableDefaultImplementation(_ stub: DAppSearchInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - func reload(model: CrowdloanYourContributionsViewModel) { + func didReceive(dAppsResult: Result) { - return cuckoo_manager.call("reload(model: CrowdloanYourContributionsViewModel)", - parameters: (model), - escapingParameters: (model), + return cuckoo_manager.call("didReceive(dAppsResult: Result)", + parameters: (dAppsResult), + escapingParameters: (dAppsResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload(model: model)) + defaultCall: __defaultImplStub!.didReceive(dAppsResult: dAppsResult)) } - func reload(returnInIntervals: [FormattedReturnInIntervalsViewModel]) { + func didReceiveFavorite(changes: [DataProviderChange]) { - return cuckoo_manager.call("reload(returnInIntervals: [FormattedReturnInIntervalsViewModel])", - parameters: (returnInIntervals), - escapingParameters: (returnInIntervals), + return cuckoo_manager.call("didReceiveFavorite(changes: [DataProviderChange])", + parameters: (changes), + escapingParameters: (changes), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload(returnInIntervals: returnInIntervals)) + defaultCall: __defaultImplStub!.didReceiveFavorite(changes: changes)) } - struct __StubbingProxy_CrowdloanYourContributionsViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppSearchInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -13432,29 +12744,19 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - func reload(model: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanYourContributionsViewModel)> where M1.MatchedType == CrowdloanYourContributionsViewModel { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewModel)>] = [wrap(matchable: model) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsViewProtocol.self, method: "reload(model: CrowdloanYourContributionsViewModel)", parameterMatchers: matchers)) + func didReceive(dAppsResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: dAppsResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchInteractorOutputProtocol.self, method: "didReceive(dAppsResult: Result)", parameterMatchers: matchers)) } - func reload(returnInIntervals: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([FormattedReturnInIntervalsViewModel])> where M1.MatchedType == [FormattedReturnInIntervalsViewModel] { - let matchers: [Cuckoo.ParameterMatcher<([FormattedReturnInIntervalsViewModel])>] = [wrap(matchable: returnInIntervals) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsViewProtocol.self, method: "reload(returnInIntervals: [FormattedReturnInIntervalsViewModel])", parameterMatchers: matchers)) + func didReceiveFavorite(changes: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([DataProviderChange])> where M1.MatchedType == [DataProviderChange] { + let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchInteractorOutputProtocol.self, method: "didReceiveFavorite(changes: [DataProviderChange])", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanYourContributionsViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppSearchInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -13466,52 +12768,24 @@ import SoraFoundation } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func reload(model: M1) -> Cuckoo.__DoNotUse<(CrowdloanYourContributionsViewModel), Void> where M1.MatchedType == CrowdloanYourContributionsViewModel { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewModel)>] = [wrap(matchable: model) { $0 }] - return cuckoo_manager.verify("reload(model: CrowdloanYourContributionsViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(dAppsResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: dAppsResult) { $0 }] + return cuckoo_manager.verify("didReceive(dAppsResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func reload(returnInIntervals: M1) -> Cuckoo.__DoNotUse<([FormattedReturnInIntervalsViewModel]), Void> where M1.MatchedType == [FormattedReturnInIntervalsViewModel] { - let matchers: [Cuckoo.ParameterMatcher<([FormattedReturnInIntervalsViewModel])>] = [wrap(matchable: returnInIntervals) { $0 }] - return cuckoo_manager.verify("reload(returnInIntervals: [FormattedReturnInIntervalsViewModel])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFavorite(changes: M1) -> Cuckoo.__DoNotUse<([DataProviderChange]), Void> where M1.MatchedType == [DataProviderChange] { + let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] + return cuckoo_manager.verify("didReceiveFavorite(changes: [DataProviderChange])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanYourContributionsViewProtocolStub: CrowdloanYourContributionsViewProtocol { - - - - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - - - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } + class DAppSearchInteractorOutputProtocolStub: DAppSearchInteractorOutputProtocol { @@ -13519,13 +12793,13 @@ import SoraFoundation - func reload(model: CrowdloanYourContributionsViewModel) { + func didReceive(dAppsResult: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func reload(returnInIntervals: [FormattedReturnInIntervalsViewModel]) { + func didReceiveFavorite(changes: [DataProviderChange]) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -13533,19 +12807,19 @@ import SoraFoundation - class MockCrowdloanYourContributionsPresenterProtocol: CrowdloanYourContributionsPresenterProtocol, Cuckoo.ProtocolMock { + class MockDAppSearchWireframeProtocol: DAppSearchWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanYourContributionsPresenterProtocol + typealias MocksType = DAppSearchWireframeProtocol - typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsPresenterProtocol - typealias Verification = __VerificationProxy_CrowdloanYourContributionsPresenterProtocol + typealias Stubbing = __StubbingProxy_DAppSearchWireframeProtocol + typealias Verification = __VerificationProxy_DAppSearchWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanYourContributionsPresenterProtocol? + private var __defaultImplStub: DAppSearchWireframeProtocol? - func enableDefaultImplementation(_ stub: CrowdloanYourContributionsPresenterProtocol) { + func enableDefaultImplementation(_ stub: DAppSearchWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -13558,21 +12832,21 @@ import SoraFoundation - func setup() { + func close(from view: DAppSearchViewProtocol?) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("close(from: DAppSearchViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.close(from: view)) } - struct __StubbingProxy_CrowdloanYourContributionsPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppSearchWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -13580,14 +12854,14 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + func close(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppSearchViewProtocol?)> where M1.OptionalMatchedType == DAppSearchViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppSearchViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchWireframeProtocol.self, method: "close(from: DAppSearchViewProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanYourContributionsPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppSearchWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -13602,15 +12876,15 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func close(from view: M1) -> Cuckoo.__DoNotUse<(DAppSearchViewProtocol?), Void> where M1.OptionalMatchedType == DAppSearchViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(DAppSearchViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(from: DAppSearchViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanYourContributionsPresenterProtocolStub: CrowdloanYourContributionsPresenterProtocol { + class DAppSearchWireframeProtocolStub: DAppSearchWireframeProtocol { @@ -13618,7 +12892,7 @@ import SoraFoundation - func setup() { + func close(from view: DAppSearchViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -13626,19 +12900,19 @@ import SoraFoundation - class MockCrowdloanYourContributionsVMFactoryProtocol: CrowdloanYourContributionsVMFactoryProtocol, Cuckoo.ProtocolMock { + class MockDAppSearchDelegate: DAppSearchDelegate, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanYourContributionsVMFactoryProtocol + typealias MocksType = DAppSearchDelegate - typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsVMFactoryProtocol - typealias Verification = __VerificationProxy_CrowdloanYourContributionsVMFactoryProtocol + typealias Stubbing = __StubbingProxy_DAppSearchDelegate + typealias Verification = __VerificationProxy_DAppSearchDelegate let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanYourContributionsVMFactoryProtocol? + private var __defaultImplStub: DAppSearchDelegate? - func enableDefaultImplementation(_ stub: CrowdloanYourContributionsVMFactoryProtocol) { + func enableDefaultImplementation(_ stub: DAppSearchDelegate) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -13651,36 +12925,21 @@ import SoraFoundation - func createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel { + func didCompleteDAppSearchResult(_ result: DAppSearchResult) { - return cuckoo_manager.call("createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel", - parameters: (input, externalContributions, amount, price, locale), - escapingParameters: (input, externalContributions, amount, price, locale), + return cuckoo_manager.call("didCompleteDAppSearchResult(_: DAppSearchResult)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.createViewModel(input: input, externalContributions: externalContributions, amount: amount, price: price, locale: locale)) - - } - - - - func createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel] { - - return cuckoo_manager.call("createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel]", - parameters: (input, externalContributions, metadata), - escapingParameters: (input, externalContributions, metadata), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.createReturnInIntervals(input: input, externalContributions: externalContributions, metadata: metadata)) + defaultCall: __defaultImplStub!.didCompleteDAppSearchResult(result)) } - struct __StubbingProxy_CrowdloanYourContributionsVMFactoryProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_DAppSearchDelegate: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -13688,19 +12947,14 @@ import SoraFoundation } - func createViewModel(input: M1, externalContributions: M2, amount: M3, price: M4, locale: M5) -> Cuckoo.ProtocolStubFunction<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, Decimal, PriceData?, Locale), CrowdloanYourContributionsViewModel> where M1.MatchedType == CrowdloanYourContributionsViewInput, M2.OptionalMatchedType == [ExternalContribution], M3.MatchedType == Decimal, M4.OptionalMatchedType == PriceData, M5.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, Decimal, PriceData?, Locale)>] = [wrap(matchable: input) { $0.0 }, wrap(matchable: externalContributions) { $0.1 }, wrap(matchable: amount) { $0.2 }, wrap(matchable: price) { $0.3 }, wrap(matchable: locale) { $0.4 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsVMFactoryProtocol.self, method: "createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel", parameterMatchers: matchers)) - } - - func createReturnInIntervals(input: M1, externalContributions: M2, metadata: M3) -> Cuckoo.ProtocolStubFunction<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, CrowdloanMetadata), [ReturnInIntervalsViewModel]> where M1.MatchedType == CrowdloanYourContributionsViewInput, M2.OptionalMatchedType == [ExternalContribution], M3.MatchedType == CrowdloanMetadata { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, CrowdloanMetadata)>] = [wrap(matchable: input) { $0.0 }, wrap(matchable: externalContributions) { $0.1 }, wrap(matchable: metadata) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsVMFactoryProtocol.self, method: "createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel]", parameterMatchers: matchers)) + func didCompleteDAppSearchResult(_ result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppSearchResult)> where M1.MatchedType == DAppSearchResult { + let matchers: [Cuckoo.ParameterMatcher<(DAppSearchResult)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchDelegate.self, method: "didCompleteDAppSearchResult(_: DAppSearchResult)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanYourContributionsVMFactoryProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_DAppSearchDelegate: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -13715,21 +12969,15 @@ import SoraFoundation @discardableResult - func createViewModel(input: M1, externalContributions: M2, amount: M3, price: M4, locale: M5) -> Cuckoo.__DoNotUse<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, Decimal, PriceData?, Locale), CrowdloanYourContributionsViewModel> where M1.MatchedType == CrowdloanYourContributionsViewInput, M2.OptionalMatchedType == [ExternalContribution], M3.MatchedType == Decimal, M4.OptionalMatchedType == PriceData, M5.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, Decimal, PriceData?, Locale)>] = [wrap(matchable: input) { $0.0 }, wrap(matchable: externalContributions) { $0.1 }, wrap(matchable: amount) { $0.2 }, wrap(matchable: price) { $0.3 }, wrap(matchable: locale) { $0.4 }] - return cuckoo_manager.verify("createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func createReturnInIntervals(input: M1, externalContributions: M2, metadata: M3) -> Cuckoo.__DoNotUse<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, CrowdloanMetadata), [ReturnInIntervalsViewModel]> where M1.MatchedType == CrowdloanYourContributionsViewInput, M2.OptionalMatchedType == [ExternalContribution], M3.MatchedType == CrowdloanMetadata { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, CrowdloanMetadata)>] = [wrap(matchable: input) { $0.0 }, wrap(matchable: externalContributions) { $0.1 }, wrap(matchable: metadata) { $0.2 }] - return cuckoo_manager.verify("createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel]", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didCompleteDAppSearchResult(_ result: M1) -> Cuckoo.__DoNotUse<(DAppSearchResult), Void> where M1.MatchedType == DAppSearchResult { + let matchers: [Cuckoo.ParameterMatcher<(DAppSearchResult)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didCompleteDAppSearchResult(_: DAppSearchResult)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanYourContributionsVMFactoryProtocolStub: CrowdloanYourContributionsVMFactoryProtocol { + class DAppSearchDelegateStub: DAppSearchDelegate { @@ -13737,60 +12985,103 @@ import SoraFoundation - func createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel { - return DefaultValueRegistry.defaultValue(for: (CrowdloanYourContributionsViewModel).self) - } - - - - func createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel] { - return DefaultValueRegistry.defaultValue(for: ([ReturnInIntervalsViewModel]).self) + func didCompleteDAppSearchResult(_ result: DAppSearchResult) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet - class MockCrowdloanYourContributionsInteractorInputProtocol: CrowdloanYourContributionsInteractorInputProtocol, Cuckoo.ProtocolMock { +import Foundation +import SoraFoundation + + + class MockAccountExportPasswordViewProtocol: AccountExportPasswordViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanYourContributionsInteractorInputProtocol + typealias MocksType = AccountExportPasswordViewProtocol - typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsInteractorInputProtocol - typealias Verification = __VerificationProxy_CrowdloanYourContributionsInteractorInputProtocol + typealias Stubbing = __StubbingProxy_AccountExportPasswordViewProtocol + typealias Verification = __VerificationProxy_AccountExportPasswordViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanYourContributionsInteractorInputProtocol? + private var __defaultImplStub: AccountExportPasswordViewProtocol? - func enableDefaultImplementation(_ stub: CrowdloanYourContributionsInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: AccountExportPasswordViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } + + + + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } + + } + - func setup() { + func setPasswordInputViewModel(_ viewModel: InputViewModelProtocol) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("setPasswordInputViewModel(_: InputViewModelProtocol)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.setPasswordInputViewModel(viewModel)) + + } + + + + func setPasswordConfirmationViewModel(_ viewModel: InputViewModelProtocol) { + + return cuckoo_manager.call("setPasswordConfirmationViewModel(_: InputViewModelProtocol)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.setPasswordConfirmationViewModel(viewModel)) } - struct __StubbingProxy_CrowdloanYourContributionsInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_AccountExportPasswordViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -13798,14 +13089,29 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") + } + + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") + } + + + func setPasswordInputViewModel(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(InputViewModelProtocol)> where M1.MatchedType == InputViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordViewProtocol.self, method: "setPasswordInputViewModel(_: InputViewModelProtocol)", parameterMatchers: matchers)) + } + + func setPasswordConfirmationViewModel(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(InputViewModelProtocol)> where M1.MatchedType == InputViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordViewProtocol.self, method: "setPasswordConfirmationViewModel(_: InputViewModelProtocol)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanYourContributionsInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_AccountExportPasswordViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -13817,18 +13123,52 @@ import SoraFoundation } + + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setPasswordInputViewModel(_ viewModel: M1) -> Cuckoo.__DoNotUse<(InputViewModelProtocol), Void> where M1.MatchedType == InputViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("setPasswordInputViewModel(_: InputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func setPasswordConfirmationViewModel(_ viewModel: M1) -> Cuckoo.__DoNotUse<(InputViewModelProtocol), Void> where M1.MatchedType == InputViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("setPasswordConfirmationViewModel(_: InputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanYourContributionsInteractorInputProtocolStub: CrowdloanYourContributionsInteractorInputProtocol { + class AccountExportPasswordViewProtocolStub: AccountExportPasswordViewProtocol { + + + + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + + + + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + + } @@ -13836,7 +13176,13 @@ import SoraFoundation - func setup() { + func setPasswordInputViewModel(_ viewModel: InputViewModelProtocol) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func setPasswordConfirmationViewModel(_ viewModel: InputViewModelProtocol) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -13844,19 +13190,19 @@ import SoraFoundation - class MockCrowdloanYourContributionsInteractorOutputProtocol: CrowdloanYourContributionsInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockAccountExportPasswordPresenterProtocol: AccountExportPasswordPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanYourContributionsInteractorOutputProtocol + typealias MocksType = AccountExportPasswordPresenterProtocol - typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsInteractorOutputProtocol - typealias Verification = __VerificationProxy_CrowdloanYourContributionsInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_AccountExportPasswordPresenterProtocol + typealias Verification = __VerificationProxy_AccountExportPasswordPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanYourContributionsInteractorOutputProtocol? + private var __defaultImplStub: AccountExportPasswordPresenterProtocol? - func enableDefaultImplementation(_ stub: CrowdloanYourContributionsInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: AccountExportPasswordPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -13869,111 +13215,36 @@ import SoraFoundation - func didReceiveExternalContributions(_ externalContributions: [ExternalContribution]) { - - return cuckoo_manager.call("didReceiveExternalContributions(_: [ExternalContribution])", - parameters: (externalContributions), - escapingParameters: (externalContributions), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveExternalContributions(externalContributions)) - - } - - - - func didReceiveBlockNumber(_ blockNumber: BlockNumber?) { - - return cuckoo_manager.call("didReceiveBlockNumber(_: BlockNumber?)", - parameters: (blockNumber), - escapingParameters: (blockNumber), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBlockNumber(blockNumber)) - - } - - - - func didReceiveBlockDuration(_ blockDuration: BlockTime) { - - return cuckoo_manager.call("didReceiveBlockDuration(_: BlockTime)", - parameters: (blockDuration), - escapingParameters: (blockDuration), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveBlockDuration(blockDuration)) - - } - - - - func didReceiveLeasingPeriod(_ leasingPeriod: LeasingPeriod) { - - return cuckoo_manager.call("didReceiveLeasingPeriod(_: LeasingPeriod)", - parameters: (leasingPeriod), - escapingParameters: (leasingPeriod), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(leasingPeriod)) - - } - - - - func didReceiveLeasingOffset(_ leasingOffset: LeasingOffset) { - - return cuckoo_manager.call("didReceiveLeasingOffset(_: LeasingOffset)", - parameters: (leasingOffset), - escapingParameters: (leasingOffset), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveLeasingOffset(leasingOffset)) - - } - - - - func didReceivePrice(_ priceData: PriceData?) { + func setup() { - return cuckoo_manager.call("didReceivePrice(_: PriceData?)", - parameters: (priceData), - escapingParameters: (priceData), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePrice(priceData)) + defaultCall: __defaultImplStub!.setup()) } - func didReceiveError(_ error: Error) { + func proceed() { - return cuckoo_manager.call("didReceiveError(_: Error)", - parameters: (error), - escapingParameters: (error), + return cuckoo_manager.call("proceed()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveError(error)) + defaultCall: __defaultImplStub!.proceed()) } - struct __StubbingProxy_CrowdloanYourContributionsInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_AccountExportPasswordPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -13981,44 +13252,19 @@ import SoraFoundation } - func didReceiveExternalContributions(_ externalContributions: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([ExternalContribution])> where M1.MatchedType == [ExternalContribution] { - let matchers: [Cuckoo.ParameterMatcher<([ExternalContribution])>] = [wrap(matchable: externalContributions) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveExternalContributions(_: [ExternalContribution])", parameterMatchers: matchers)) - } - - func didReceiveBlockNumber(_ blockNumber: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BlockNumber?)> where M1.OptionalMatchedType == BlockNumber { - let matchers: [Cuckoo.ParameterMatcher<(BlockNumber?)>] = [wrap(matchable: blockNumber) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveBlockNumber(_: BlockNumber?)", parameterMatchers: matchers)) - } - - func didReceiveBlockDuration(_ blockDuration: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BlockTime)> where M1.MatchedType == BlockTime { - let matchers: [Cuckoo.ParameterMatcher<(BlockTime)>] = [wrap(matchable: blockDuration) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveBlockDuration(_: BlockTime)", parameterMatchers: matchers)) - } - - func didReceiveLeasingPeriod(_ leasingPeriod: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LeasingPeriod)> where M1.MatchedType == LeasingPeriod { - let matchers: [Cuckoo.ParameterMatcher<(LeasingPeriod)>] = [wrap(matchable: leasingPeriod) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(_: LeasingPeriod)", parameterMatchers: matchers)) - } - - func didReceiveLeasingOffset(_ leasingOffset: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LeasingOffset)> where M1.MatchedType == LeasingOffset { - let matchers: [Cuckoo.ParameterMatcher<(LeasingOffset)>] = [wrap(matchable: leasingOffset) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(_: LeasingOffset)", parameterMatchers: matchers)) - } - - func didReceivePrice(_ priceData: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PriceData?)> where M1.OptionalMatchedType == PriceData { - let matchers: [Cuckoo.ParameterMatcher<(PriceData?)>] = [wrap(matchable: priceData) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceivePrice(_: PriceData?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func didReceiveError(_ error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveError(_: Error)", parameterMatchers: matchers)) + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CrowdloanYourContributionsInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_AccountExportPasswordPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -14033,51 +13279,21 @@ import SoraFoundation @discardableResult - func didReceiveExternalContributions(_ externalContributions: M1) -> Cuckoo.__DoNotUse<([ExternalContribution]), Void> where M1.MatchedType == [ExternalContribution] { - let matchers: [Cuckoo.ParameterMatcher<([ExternalContribution])>] = [wrap(matchable: externalContributions) { $0 }] - return cuckoo_manager.verify("didReceiveExternalContributions(_: [ExternalContribution])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBlockNumber(_ blockNumber: M1) -> Cuckoo.__DoNotUse<(BlockNumber?), Void> where M1.OptionalMatchedType == BlockNumber { - let matchers: [Cuckoo.ParameterMatcher<(BlockNumber?)>] = [wrap(matchable: blockNumber) { $0 }] - return cuckoo_manager.verify("didReceiveBlockNumber(_: BlockNumber?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBlockDuration(_ blockDuration: M1) -> Cuckoo.__DoNotUse<(BlockTime), Void> where M1.MatchedType == BlockTime { - let matchers: [Cuckoo.ParameterMatcher<(BlockTime)>] = [wrap(matchable: blockDuration) { $0 }] - return cuckoo_manager.verify("didReceiveBlockDuration(_: BlockTime)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveLeasingPeriod(_ leasingPeriod: M1) -> Cuckoo.__DoNotUse<(LeasingPeriod), Void> where M1.MatchedType == LeasingPeriod { - let matchers: [Cuckoo.ParameterMatcher<(LeasingPeriod)>] = [wrap(matchable: leasingPeriod) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingPeriod(_: LeasingPeriod)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveLeasingOffset(_ leasingOffset: M1) -> Cuckoo.__DoNotUse<(LeasingOffset), Void> where M1.MatchedType == LeasingOffset { - let matchers: [Cuckoo.ParameterMatcher<(LeasingOffset)>] = [wrap(matchable: leasingOffset) { $0 }] - return cuckoo_manager.verify("didReceiveLeasingOffset(_: LeasingOffset)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePrice(_ priceData: M1) -> Cuckoo.__DoNotUse<(PriceData?), Void> where M1.OptionalMatchedType == PriceData { - let matchers: [Cuckoo.ParameterMatcher<(PriceData?)>] = [wrap(matchable: priceData) { $0 }] - return cuckoo_manager.verify("didReceivePrice(_: PriceData?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveError(_ error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return cuckoo_manager.verify("didReceiveError(_: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceed() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CrowdloanYourContributionsInteractorOutputProtocolStub: CrowdloanYourContributionsInteractorOutputProtocol { + class AccountExportPasswordPresenterProtocolStub: AccountExportPasswordPresenterProtocol { @@ -14085,43 +13301,13 @@ import SoraFoundation - func didReceiveExternalContributions(_ externalContributions: [ExternalContribution]) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveBlockNumber(_ blockNumber: BlockNumber?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveBlockDuration(_ blockDuration: BlockTime) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveLeasingPeriod(_ leasingPeriod: LeasingPeriod) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveLeasingOffset(_ leasingOffset: LeasingOffset) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceivePrice(_ priceData: PriceData?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveError(_ error: Error) { + func proceed() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -14129,19 +13315,19 @@ import SoraFoundation - class MockCrowdloanYourContributionsWireframeProtocol: CrowdloanYourContributionsWireframeProtocol, Cuckoo.ProtocolMock { + class MockAccountExportPasswordInteractorInputProtocol: AccountExportPasswordInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CrowdloanYourContributionsWireframeProtocol + typealias MocksType = AccountExportPasswordInteractorInputProtocol - typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsWireframeProtocol - typealias Verification = __VerificationProxy_CrowdloanYourContributionsWireframeProtocol + typealias Stubbing = __StubbingProxy_AccountExportPasswordInteractorInputProtocol + typealias Verification = __VerificationProxy_AccountExportPasswordInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CrowdloanYourContributionsWireframeProtocol? + private var __defaultImplStub: AccountExportPasswordInteractorInputProtocol? - func enableDefaultImplementation(_ stub: CrowdloanYourContributionsWireframeProtocol) { + func enableDefaultImplementation(_ stub: AccountExportPasswordInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -14152,8 +13338,23 @@ import SoraFoundation + + + func exportAccount(password: String) { + + return cuckoo_manager.call("exportAccount(password: String)", + parameters: (password), + escapingParameters: (password), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.exportAccount(password: password)) + + } + - struct __StubbingProxy_CrowdloanYourContributionsWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_AccountExportPasswordInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -14161,9 +13362,14 @@ import SoraFoundation } + func exportAccount(password: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: password) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordInteractorInputProtocol.self, method: "exportAccount(password: String)", parameterMatchers: matchers)) + } + } - struct __VerificationProxy_CrowdloanYourContributionsWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_AccountExportPasswordInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -14177,37 +13383,44 @@ import SoraFoundation + @discardableResult + func exportAccount(password: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: password) { $0 }] + return cuckoo_manager.verify("exportAccount(password: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } - class CrowdloanYourContributionsWireframeProtocolStub: CrowdloanYourContributionsWireframeProtocol { + class AccountExportPasswordInteractorInputProtocolStub: AccountExportPasswordInteractorInputProtocol { + + + func exportAccount(password: String) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + } -import Cuckoo -@testable import novawallet - -import Foundation - - class MockCustomCrowdloanDelegate: CustomCrowdloanDelegate, Cuckoo.ProtocolMock { + class MockAccountExportPasswordInteractorOutputProtocol: AccountExportPasswordInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CustomCrowdloanDelegate + typealias MocksType = AccountExportPasswordInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_CustomCrowdloanDelegate - typealias Verification = __VerificationProxy_CustomCrowdloanDelegate + typealias Stubbing = __StubbingProxy_AccountExportPasswordInteractorOutputProtocol + typealias Verification = __VerificationProxy_AccountExportPasswordInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CustomCrowdloanDelegate? + private var __defaultImplStub: AccountExportPasswordInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: CustomCrowdloanDelegate) { + func enableDefaultImplementation(_ stub: AccountExportPasswordInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -14220,36 +13433,56 @@ import Foundation - func didReceive(bonusService: CrowdloanBonusServiceProtocol) { + func didExport(json: RestoreJson) { - return cuckoo_manager.call("didReceive(bonusService: CrowdloanBonusServiceProtocol)", - parameters: (bonusService), - escapingParameters: (bonusService), + return cuckoo_manager.call("didExport(json: RestoreJson)", + parameters: (json), + escapingParameters: (json), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(bonusService: bonusService)) + defaultCall: __defaultImplStub!.didExport(json: json)) } - - struct __StubbingProxy_CustomCrowdloanDelegate: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func didReceive(bonusService: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanBonusServiceProtocol)> where M1.MatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanBonusServiceProtocol)>] = [wrap(matchable: bonusService) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomCrowdloanDelegate.self, method: "didReceive(bonusService: CrowdloanBonusServiceProtocol)", parameterMatchers: matchers)) + + + func didReceive(error: Error) { + + return cuckoo_manager.call("didReceive(error: Error)", + parameters: (error), + escapingParameters: (error), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(error: error)) + + } + + + struct __StubbingProxy_AccountExportPasswordInteractorOutputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func didExport(json: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RestoreJson)> where M1.MatchedType == RestoreJson { + let matchers: [Cuckoo.ParameterMatcher<(RestoreJson)>] = [wrap(matchable: json) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordInteractorOutputProtocol.self, method: "didExport(json: RestoreJson)", parameterMatchers: matchers)) + } + + func didReceive(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordInteractorOutputProtocol.self, method: "didReceive(error: Error)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CustomCrowdloanDelegate: Cuckoo.VerificationProxy { + struct __VerificationProxy_AccountExportPasswordInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -14264,15 +13497,21 @@ import Foundation @discardableResult - func didReceive(bonusService: M1) -> Cuckoo.__DoNotUse<(CrowdloanBonusServiceProtocol), Void> where M1.MatchedType == CrowdloanBonusServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(CrowdloanBonusServiceProtocol)>] = [wrap(matchable: bonusService) { $0 }] - return cuckoo_manager.verify("didReceive(bonusService: CrowdloanBonusServiceProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didExport(json: M1) -> Cuckoo.__DoNotUse<(RestoreJson), Void> where M1.MatchedType == RestoreJson { + let matchers: [Cuckoo.ParameterMatcher<(RestoreJson)>] = [wrap(matchable: json) { $0 }] + return cuckoo_manager.verify("didExport(json: RestoreJson)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return cuckoo_manager.verify("didReceive(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CustomCrowdloanDelegateStub: CustomCrowdloanDelegate { + class AccountExportPasswordInteractorOutputProtocolStub: AccountExportPasswordInteractorOutputProtocol { @@ -14280,205 +13519,251 @@ import Foundation - func didReceive(bonusService: CrowdloanBonusServiceProtocol) { + func didExport(json: RestoreJson) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceive(error: Error) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import SoraFoundation - - class MockReferralCrowdloanViewProtocol: ReferralCrowdloanViewProtocol, Cuckoo.ProtocolMock { + class MockAccountExportPasswordWireframeProtocol: AccountExportPasswordWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ReferralCrowdloanViewProtocol + typealias MocksType = AccountExportPasswordWireframeProtocol - typealias Stubbing = __StubbingProxy_ReferralCrowdloanViewProtocol - typealias Verification = __VerificationProxy_ReferralCrowdloanViewProtocol + typealias Stubbing = __StubbingProxy_AccountExportPasswordWireframeProtocol + typealias Verification = __VerificationProxy_AccountExportPasswordWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ReferralCrowdloanViewProtocol? + private var __defaultImplStub: AccountExportPasswordWireframeProtocol? - func enableDefaultImplementation(_ stub: ReferralCrowdloanViewProtocol) { + func enableDefaultImplementation(_ stub: AccountExportPasswordWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - - - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } - - } - - func didReceiveLearnMore(viewModel: LearnMoreViewModel) { + func showJSONExport(_ json: RestoreJson, from view: AccountExportPasswordViewProtocol?) { - return cuckoo_manager.call("didReceiveLearnMore(viewModel: LearnMoreViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("showJSONExport(_: RestoreJson, from: AccountExportPasswordViewProtocol?)", + parameters: (json, view), + escapingParameters: (json, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveLearnMore(viewModel: viewModel)) + defaultCall: __defaultImplStub!.showJSONExport(json, from: view)) } - func didReceiveReferral(viewModel: ReferralCrowdloanViewModel) { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("didReceiveReferral(viewModel: ReferralCrowdloanViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveReferral(viewModel: viewModel)) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - func didReceiveInput(viewModel: InputViewModelProtocol) { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("didReceiveInput(viewModel: InputViewModelProtocol)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } + + struct __StubbingProxy_AccountExportPasswordWireframeProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func showJSONExport(_ json: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(RestoreJson, AccountExportPasswordViewProtocol?)> where M1.MatchedType == RestoreJson, M2.OptionalMatchedType == AccountExportPasswordViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(RestoreJson, AccountExportPasswordViewProtocol?)>] = [wrap(matchable: json) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordWireframeProtocol.self, method: "showJSONExport(_: RestoreJson, from: AccountExportPasswordViewProtocol?)", parameterMatchers: matchers)) + } + + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_AccountExportPasswordWireframeProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func showJSONExport(_ json: M1, from view: M2) -> Cuckoo.__DoNotUse<(RestoreJson, AccountExportPasswordViewProtocol?), Void> where M1.MatchedType == RestoreJson, M2.OptionalMatchedType == AccountExportPasswordViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(RestoreJson, AccountExportPasswordViewProtocol?)>] = [wrap(matchable: json) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("showJSONExport(_: RestoreJson, from: AccountExportPasswordViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class AccountExportPasswordWireframeProtocolStub: AccountExportPasswordWireframeProtocol { + + + + - func didReceiveShouldInputCode() { - - return cuckoo_manager.call("didReceiveShouldInputCode()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveShouldInputCode()) - + + func showJSONExport(_ json: RestoreJson, from view: AccountExportPasswordViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveShouldAgreeTerms() { - - return cuckoo_manager.call("didReceiveShouldAgreeTerms()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveShouldAgreeTerms()) - + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoading() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + +import Cuckoo +@testable import novawallet + +import Foundation +import SoraFoundation + + + class MockExportGenericViewProtocol: ExportGenericViewProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = ExportGenericViewProtocol + + typealias Stubbing = __StubbingProxy_ExportGenericViewProtocol + typealias Verification = __VerificationProxy_ExportGenericViewProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: ExportGenericViewProtocol? + + func enableDefaultImplementation(_ stub: ExportGenericViewProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + + + + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } - return cuckoo_manager.call("didStartLoading()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didStartLoading()) + } + + + + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } + + + + - func didStopLoading() { + func set(viewModel: ExportGenericViewModel) { - return cuckoo_manager.call("didStopLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("set(viewModel: ExportGenericViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopLoading()) + defaultCall: __defaultImplStub!.set(viewModel: viewModel)) } - struct __StubbingProxy_ReferralCrowdloanViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ExportGenericViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -14486,64 +13771,24 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") - } - - - func didReceiveLearnMore(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LearnMoreViewModel)> where M1.MatchedType == LearnMoreViewModel { - let matchers: [Cuckoo.ParameterMatcher<(LearnMoreViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveLearnMore(viewModel: LearnMoreViewModel)", parameterMatchers: matchers)) - } - - func didReceiveReferral(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ReferralCrowdloanViewModel)> where M1.MatchedType == ReferralCrowdloanViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ReferralCrowdloanViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveReferral(viewModel: ReferralCrowdloanViewModel)", parameterMatchers: matchers)) - } - - func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(InputViewModelProtocol)> where M1.MatchedType == InputViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveInput(viewModel: InputViewModelProtocol)", parameterMatchers: matchers)) - } - - func didReceiveShouldInputCode() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveShouldInputCode()", parameterMatchers: matchers)) - } - - func didReceiveShouldAgreeTerms() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveShouldAgreeTerms()", parameterMatchers: matchers)) - } - - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) - } - - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + func set(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewModel)> where M1.MatchedType == ExportGenericViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportGenericViewProtocol.self, method: "set(viewModel: ExportGenericViewModel)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ReferralCrowdloanViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ExportGenericViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -14565,64 +13810,18 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveLearnMore(viewModel: M1) -> Cuckoo.__DoNotUse<(LearnMoreViewModel), Void> where M1.MatchedType == LearnMoreViewModel { - let matchers: [Cuckoo.ParameterMatcher<(LearnMoreViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveLearnMore(viewModel: LearnMoreViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveReferral(viewModel: M1) -> Cuckoo.__DoNotUse<(ReferralCrowdloanViewModel), Void> where M1.MatchedType == ReferralCrowdloanViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ReferralCrowdloanViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveReferral(viewModel: ReferralCrowdloanViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(InputViewModelProtocol), Void> where M1.MatchedType == InputViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveInput(viewModel: InputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveShouldInputCode() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didReceiveShouldInputCode()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveShouldAgreeTerms() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didReceiveShouldAgreeTerms()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func set(viewModel: M1) -> Cuckoo.__DoNotUse<(ExportGenericViewModel), Void> where M1.MatchedType == ExportGenericViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("set(viewModel: ExportGenericViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ReferralCrowdloanViewProtocolStub: ReferralCrowdloanViewProtocol { + class ExportGenericViewProtocolStub: ExportGenericViewProtocol { @@ -14641,24 +13840,6 @@ import SoraFoundation } } - - - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } @@ -14666,43 +13847,7 @@ import SoraFoundation - func didReceiveLearnMore(viewModel: LearnMoreViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveReferral(viewModel: ReferralCrowdloanViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveInput(viewModel: InputViewModelProtocol) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveShouldInputCode() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveShouldAgreeTerms() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didStartLoading() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didStopLoading() { + func set(viewModel: ExportGenericViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -14710,19 +13855,19 @@ import SoraFoundation - class MockReferralCrowdloanPresenterProtocol: ReferralCrowdloanPresenterProtocol, Cuckoo.ProtocolMock { + class MockExportGenericPresenterProtocol: ExportGenericPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ReferralCrowdloanPresenterProtocol + typealias MocksType = ExportGenericPresenterProtocol - typealias Stubbing = __StubbingProxy_ReferralCrowdloanPresenterProtocol - typealias Verification = __VerificationProxy_ReferralCrowdloanPresenterProtocol + typealias Stubbing = __StubbingProxy_ExportGenericPresenterProtocol + typealias Verification = __VerificationProxy_ExportGenericPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ReferralCrowdloanPresenterProtocol? + private var __defaultImplStub: ExportGenericPresenterProtocol? - func enableDefaultImplementation(_ stub: ReferralCrowdloanPresenterProtocol) { + func enableDefaultImplementation(_ stub: ExportGenericPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -14750,96 +13895,36 @@ import SoraFoundation - func update(referralCode: String) { + func activateExport() { - return cuckoo_manager.call("update(referralCode: String)", - parameters: (referralCode), - escapingParameters: (referralCode), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.update(referralCode: referralCode)) - - } - - - - func applyDefaultCode() { - - return cuckoo_manager.call("applyDefaultCode()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.applyDefaultCode()) - - } - - - - func applyInputCode() { - - return cuckoo_manager.call("applyInputCode()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.applyInputCode()) - - } - - - - func setTermsAgreed(value: Bool) { - - return cuckoo_manager.call("setTermsAgreed(value: Bool)", - parameters: (value), - escapingParameters: (value), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setTermsAgreed(value: value)) - - } - - - - func presentTerms() { - - return cuckoo_manager.call("presentTerms()", + return cuckoo_manager.call("activateExport()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentTerms()) + defaultCall: __defaultImplStub!.activateExport()) } - func presentLearnMore() { + func activateAdvancedSettings() { - return cuckoo_manager.call("presentLearnMore()", + return cuckoo_manager.call("activateAdvancedSettings()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentLearnMore()) + defaultCall: __defaultImplStub!.activateAdvancedSettings()) } - struct __StubbingProxy_ReferralCrowdloanPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ExportGenericPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -14849,42 +13934,22 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func update(referralCode: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: referralCode) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "update(referralCode: String)", parameterMatchers: matchers)) - } - - func applyDefaultCode() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "applyDefaultCode()", parameterMatchers: matchers)) - } - - func applyInputCode() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "applyInputCode()", parameterMatchers: matchers)) - } - - func setTermsAgreed(value: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: value) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "setTermsAgreed(value: Bool)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockExportGenericPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func presentTerms() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func activateExport() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "presentTerms()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockExportGenericPresenterProtocol.self, method: "activateExport()", parameterMatchers: matchers)) } - func presentLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func activateAdvancedSettings() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "presentLearnMore()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockExportGenericPresenterProtocol.self, method: "activateAdvancedSettings()", parameterMatchers: matchers)) } } - struct __VerificationProxy_ReferralCrowdloanPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ExportGenericPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -14905,45 +13970,21 @@ import SoraFoundation } @discardableResult - func update(referralCode: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: referralCode) { $0 }] - return cuckoo_manager.verify("update(referralCode: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func applyDefaultCode() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyDefaultCode()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func applyInputCode() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyInputCode()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func setTermsAgreed(value: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: value) { $0 }] - return cuckoo_manager.verify("setTermsAgreed(value: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func presentTerms() -> Cuckoo.__DoNotUse<(), Void> { + func activateExport() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentTerms()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("activateExport()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentLearnMore() -> Cuckoo.__DoNotUse<(), Void> { + func activateAdvancedSettings() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("activateAdvancedSettings()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ReferralCrowdloanPresenterProtocolStub: ReferralCrowdloanPresenterProtocol { + class ExportGenericPresenterProtocolStub: ExportGenericPresenterProtocol { @@ -14957,37 +13998,13 @@ import SoraFoundation - func update(referralCode: String) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func applyDefaultCode() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func applyInputCode() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func setTermsAgreed(value: Bool) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func presentTerms() { + func activateExport() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentLearnMore() { + func activateAdvancedSettings() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -14995,19 +14012,19 @@ import SoraFoundation - class MockReferralCrowdloanWireframeProtocol: ReferralCrowdloanWireframeProtocol, Cuckoo.ProtocolMock { + class MockExportGenericWireframeProtocol: ExportGenericWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ReferralCrowdloanWireframeProtocol + typealias MocksType = ExportGenericWireframeProtocol - typealias Stubbing = __StubbingProxy_ReferralCrowdloanWireframeProtocol - typealias Verification = __VerificationProxy_ReferralCrowdloanWireframeProtocol + typealias Stubbing = __StubbingProxy_ExportGenericWireframeProtocol + typealias Verification = __VerificationProxy_ExportGenericWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ReferralCrowdloanWireframeProtocol? + private var __defaultImplStub: ExportGenericWireframeProtocol? - func enableDefaultImplementation(_ stub: ReferralCrowdloanWireframeProtocol) { + func enableDefaultImplementation(_ stub: ExportGenericWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -15020,31 +14037,31 @@ import SoraFoundation - func complete(on view: ReferralCrowdloanViewProtocol?) { + func close(view: ExportGenericViewProtocol?) { - return cuckoo_manager.call("complete(on: ReferralCrowdloanViewProtocol?)", + return cuckoo_manager.call("close(view: ExportGenericViewProtocol?)", parameters: (view), escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.complete(on: view)) + defaultCall: __defaultImplStub!.close(view: view)) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { - return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", - parameters: (url, view, style), - escapingParameters: (url, view, style), + return cuckoo_manager.call("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", + parameters: (view, secretSource, settings), + escapingParameters: (view, secretSource, settings), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) + defaultCall: __defaultImplStub!.showAdvancedSettings(from: view, secretSource: secretSource, settings: settings)) } @@ -15078,8 +14095,23 @@ import SoraFoundation } + + + func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + + return cuckoo_manager.call("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", + parameters: (source, view, completionHandler), + escapingParameters: (source, view, completionHandler), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.share(source: source, from: view, with: completionHandler)) + + } + - struct __StubbingProxy_ReferralCrowdloanWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ExportGenericWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -15087,29 +14119,34 @@ import SoraFoundation } - func complete(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ReferralCrowdloanViewProtocol?)> where M1.OptionalMatchedType == ReferralCrowdloanViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ReferralCrowdloanViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanWireframeProtocol.self, method: "complete(on: ReferralCrowdloanViewProtocol?)", parameterMatchers: matchers)) + func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?)> where M1.OptionalMatchedType == ExportGenericViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "close(view: ExportGenericViewProtocol?)", parameterMatchers: matchers)) } - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) + func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { + let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ReferralCrowdloanWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ExportGenericWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -15124,15 +14161,15 @@ import SoraFoundation @discardableResult - func complete(on view: M1) -> Cuckoo.__DoNotUse<(ReferralCrowdloanViewProtocol?), Void> where M1.OptionalMatchedType == ReferralCrowdloanViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ReferralCrowdloanViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("complete(on: ReferralCrowdloanViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func close(view: M1) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(view: ExportGenericViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] + return cuckoo_manager.verify("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -15147,10 +14184,16 @@ import SoraFoundation return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.__DoNotUse<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?), Void> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { + let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] + return cuckoo_manager.verify("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } - class ReferralCrowdloanWireframeProtocolStub: ReferralCrowdloanWireframeProtocol { + class ExportGenericWireframeProtocolStub: ExportGenericWireframeProtocol { @@ -15158,13 +14201,13 @@ import SoraFoundation - func complete(on view: ReferralCrowdloanViewProtocol?) { + func close(view: ExportGenericViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -15180,81 +14223,61 @@ import SoraFoundation return DefaultValueRegistry.defaultValue(for: (Void).self) } + + + func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + } import Cuckoo @testable import novawallet +import IrohaCrypto + - class MockDAppAuthConfirmViewProtocol: DAppAuthConfirmViewProtocol, Cuckoo.ProtocolMock { + class MockExportMnemonicInteractorInputProtocol: ExportMnemonicInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppAuthConfirmViewProtocol + typealias MocksType = ExportMnemonicInteractorInputProtocol - typealias Stubbing = __StubbingProxy_DAppAuthConfirmViewProtocol - typealias Verification = __VerificationProxy_DAppAuthConfirmViewProtocol + typealias Stubbing = __StubbingProxy_ExportMnemonicInteractorInputProtocol + typealias Verification = __VerificationProxy_ExportMnemonicInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppAuthConfirmViewProtocol? + private var __defaultImplStub: ExportMnemonicInteractorInputProtocol? - func enableDefaultImplementation(_ stub: DAppAuthConfirmViewProtocol) { + func enableDefaultImplementation(_ stub: ExportMnemonicInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - func didReceive(viewModel: DAppAuthViewModel) { + func fetchExportData() { - return cuckoo_manager.call("didReceive(viewModel: DAppAuthViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("fetchExportData()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) + defaultCall: __defaultImplStub!.fetchExportData()) } - struct __StubbingProxy_DAppAuthConfirmViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ExportMnemonicInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -15262,24 +14285,14 @@ import Cuckoo } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthViewModel)> where M1.MatchedType == DAppAuthViewModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmViewProtocol.self, method: "didReceive(viewModel: DAppAuthViewModel)", parameterMatchers: matchers)) + func fetchExportData() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicInteractorInputProtocol.self, method: "fetchExportData()", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppAuthConfirmViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ExportMnemonicInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -15291,46 +14304,18 @@ import Cuckoo } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(DAppAuthViewModel), Void> where M1.MatchedType == DAppAuthViewModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceive(viewModel: DAppAuthViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func fetchExportData() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("fetchExportData()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppAuthConfirmViewProtocolStub: DAppAuthConfirmViewProtocol { - - - - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - - - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } + class ExportMnemonicInteractorInputProtocolStub: ExportMnemonicInteractorInputProtocol { @@ -15338,7 +14323,7 @@ import Cuckoo - func didReceive(viewModel: DAppAuthViewModel) { + func fetchExportData() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -15346,19 +14331,19 @@ import Cuckoo - class MockDAppAuthConfirmPresenterProtocol: DAppAuthConfirmPresenterProtocol, Cuckoo.ProtocolMock { + class MockExportMnemonicInteractorOutputProtocol: ExportMnemonicInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppAuthConfirmPresenterProtocol + typealias MocksType = ExportMnemonicInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_DAppAuthConfirmPresenterProtocol - typealias Verification = __VerificationProxy_DAppAuthConfirmPresenterProtocol + typealias Stubbing = __StubbingProxy_ExportMnemonicInteractorOutputProtocol + typealias Verification = __VerificationProxy_ExportMnemonicInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppAuthConfirmPresenterProtocol? + private var __defaultImplStub: ExportMnemonicInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: DAppAuthConfirmPresenterProtocol) { + func enableDefaultImplementation(_ stub: ExportMnemonicInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -15371,51 +14356,36 @@ import Cuckoo - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - - } - - - - func allow() { + func didReceive(exportData: ExportMnemonicData) { - return cuckoo_manager.call("allow()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(exportData: ExportMnemonicData)", + parameters: (exportData), + escapingParameters: (exportData), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.allow()) + defaultCall: __defaultImplStub!.didReceive(exportData: exportData)) } - func deny() { + func didReceive(error: Error) { - return cuckoo_manager.call("deny()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(error: Error)", + parameters: (error), + escapingParameters: (error), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.deny()) + defaultCall: __defaultImplStub!.didReceive(error: error)) } - struct __StubbingProxy_DAppAuthConfirmPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ExportMnemonicInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -15423,24 +14393,19 @@ import Cuckoo } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func allow() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmPresenterProtocol.self, method: "allow()", parameterMatchers: matchers)) + func didReceive(exportData: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportMnemonicData)> where M1.MatchedType == ExportMnemonicData { + let matchers: [Cuckoo.ParameterMatcher<(ExportMnemonicData)>] = [wrap(matchable: exportData) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicInteractorOutputProtocol.self, method: "didReceive(exportData: ExportMnemonicData)", parameterMatchers: matchers)) } - func deny() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmPresenterProtocol.self, method: "deny()", parameterMatchers: matchers)) + func didReceive(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicInteractorOutputProtocol.self, method: "didReceive(error: Error)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppAuthConfirmPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ExportMnemonicInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -15455,27 +14420,21 @@ import Cuckoo @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func allow() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("allow()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(exportData: M1) -> Cuckoo.__DoNotUse<(ExportMnemonicData), Void> where M1.MatchedType == ExportMnemonicData { + let matchers: [Cuckoo.ParameterMatcher<(ExportMnemonicData)>] = [wrap(matchable: exportData) { $0 }] + return cuckoo_manager.verify("didReceive(exportData: ExportMnemonicData)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func deny() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("deny()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return cuckoo_manager.verify("didReceive(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppAuthConfirmPresenterProtocolStub: DAppAuthConfirmPresenterProtocol { + class ExportMnemonicInteractorOutputProtocolStub: ExportMnemonicInteractorOutputProtocol { @@ -15483,19 +14442,13 @@ import Cuckoo - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func allow() { + func didReceive(exportData: ExportMnemonicData) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func deny() { + func didReceive(error: Error) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -15503,19 +14456,19 @@ import Cuckoo - class MockDAppAuthConfirmWireframeProtocol: DAppAuthConfirmWireframeProtocol, Cuckoo.ProtocolMock { + class MockExportMnemonicWireframeProtocol: ExportMnemonicWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppAuthConfirmWireframeProtocol + typealias MocksType = ExportMnemonicWireframeProtocol - typealias Stubbing = __StubbingProxy_DAppAuthConfirmWireframeProtocol - typealias Verification = __VerificationProxy_DAppAuthConfirmWireframeProtocol + typealias Stubbing = __StubbingProxy_ExportMnemonicWireframeProtocol + typealias Verification = __VerificationProxy_ExportMnemonicWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppAuthConfirmWireframeProtocol? + private var __defaultImplStub: ExportMnemonicWireframeProtocol? - func enableDefaultImplementation(_ stub: DAppAuthConfirmWireframeProtocol) { + func enableDefaultImplementation(_ stub: ExportMnemonicWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -15528,36 +14481,136 @@ import Cuckoo - func close(from view: DAppAuthConfirmViewProtocol?) { + func openConfirmationForMnemonic(_ mnemonic: IRMnemonicProtocol, from view: ExportGenericViewProtocol?) { - return cuckoo_manager.call("close(from: DAppAuthConfirmViewProtocol?)", + return cuckoo_manager.call("openConfirmationForMnemonic(_: IRMnemonicProtocol, from: ExportGenericViewProtocol?)", + parameters: (mnemonic, view), + escapingParameters: (mnemonic, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.openConfirmationForMnemonic(mnemonic, from: view)) + + } + + + + func close(view: ExportGenericViewProtocol?) { + + return cuckoo_manager.call("close(view: ExportGenericViewProtocol?)", parameters: (view), escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(from: view)) + defaultCall: __defaultImplStub!.close(view: view)) } - - struct __StubbingProxy_DAppAuthConfirmWireframeProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - + + + func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + + return cuckoo_manager.call("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", + parameters: (view, secretSource, settings), + escapingParameters: (view, secretSource, settings), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showAdvancedSettings(from: view, secretSource: secretSource, settings: settings)) + + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + + } + + + + func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + + return cuckoo_manager.call("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", + parameters: (source, view, completionHandler), + escapingParameters: (source, view, completionHandler), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.share(source: source, from: view, with: completionHandler)) + + } + + + struct __StubbingProxy_ExportMnemonicWireframeProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } - func close(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthConfirmViewProtocol?)> where M1.OptionalMatchedType == DAppAuthConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthConfirmWireframeProtocol.self, method: "close(from: DAppAuthConfirmViewProtocol?)", parameterMatchers: matchers)) + + func openConfirmationForMnemonic(_ mnemonic: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(IRMnemonicProtocol, ExportGenericViewProtocol?)> where M1.MatchedType == IRMnemonicProtocol, M2.OptionalMatchedType == ExportGenericViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(IRMnemonicProtocol, ExportGenericViewProtocol?)>] = [wrap(matchable: mnemonic) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "openConfirmationForMnemonic(_: IRMnemonicProtocol, from: ExportGenericViewProtocol?)", parameterMatchers: matchers)) + } + + func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?)> where M1.OptionalMatchedType == ExportGenericViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "close(view: ExportGenericViewProtocol?)", parameterMatchers: matchers)) + } + + func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", parameterMatchers: matchers)) + } + + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { + let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppAuthConfirmWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ExportMnemonicWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -15572,15 +14625,45 @@ import Cuckoo @discardableResult - func close(from view: M1) -> Cuckoo.__DoNotUse<(DAppAuthConfirmViewProtocol?), Void> where M1.OptionalMatchedType == DAppAuthConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(from: DAppAuthConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func openConfirmationForMnemonic(_ mnemonic: M1, from view: M2) -> Cuckoo.__DoNotUse<(IRMnemonicProtocol, ExportGenericViewProtocol?), Void> where M1.MatchedType == IRMnemonicProtocol, M2.OptionalMatchedType == ExportGenericViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(IRMnemonicProtocol, ExportGenericViewProtocol?)>] = [wrap(matchable: mnemonic) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("openConfirmationForMnemonic(_: IRMnemonicProtocol, from: ExportGenericViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func close(view: M1) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(view: ExportGenericViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] + return cuckoo_manager.verify("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.__DoNotUse<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?), Void> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { + let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] + return cuckoo_manager.verify("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppAuthConfirmWireframeProtocolStub: DAppAuthConfirmWireframeProtocol { + class ExportMnemonicWireframeProtocolStub: ExportMnemonicWireframeProtocol { @@ -15588,27 +14671,62 @@ import Cuckoo - func close(from view: DAppAuthConfirmViewProtocol?) { + func openConfirmationForMnemonic(_ mnemonic: IRMnemonicProtocol, from view: ExportGenericViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func close(view: ExportGenericViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet + +import Foundation - class MockDAppAuthDelegate: DAppAuthDelegate, Cuckoo.ProtocolMock { + + class MockExportRestoreJsonWireframeProtocol: ExportRestoreJsonWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppAuthDelegate + typealias MocksType = ExportRestoreJsonWireframeProtocol - typealias Stubbing = __StubbingProxy_DAppAuthDelegate - typealias Verification = __VerificationProxy_DAppAuthDelegate + typealias Stubbing = __StubbingProxy_ExportRestoreJsonWireframeProtocol + typealias Verification = __VerificationProxy_ExportRestoreJsonWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppAuthDelegate? + private var __defaultImplStub: ExportRestoreJsonWireframeProtocol? - func enableDefaultImplementation(_ stub: DAppAuthDelegate) { + func enableDefaultImplementation(_ stub: ExportRestoreJsonWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -15621,21 +14739,81 @@ import Cuckoo - func didReceiveAuthResponse(_ response: DAppAuthResponse, for request: DAppAuthRequest) { + func close(view: ExportGenericViewProtocol?) { - return cuckoo_manager.call("didReceiveAuthResponse(_: DAppAuthResponse, for: DAppAuthRequest)", - parameters: (response, request), - escapingParameters: (response, request), + return cuckoo_manager.call("close(view: ExportGenericViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAuthResponse(response, for: request)) + defaultCall: __defaultImplStub!.close(view: view)) + + } + + + + func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + + return cuckoo_manager.call("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", + parameters: (view, secretSource, settings), + escapingParameters: (view, secretSource, settings), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showAdvancedSettings(from: view, secretSource: secretSource, settings: settings)) + + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + + } + + + + func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + + return cuckoo_manager.call("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", + parameters: (source, view, completionHandler), + escapingParameters: (source, view, completionHandler), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.share(source: source, from: view, with: completionHandler)) } - struct __StubbingProxy_DAppAuthDelegate: Cuckoo.StubbingProxy { + struct __StubbingProxy_ExportRestoreJsonWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -15643,14 +14821,34 @@ import Cuckoo } - func didReceiveAuthResponse(_ response: M1, for request: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthResponse, DAppAuthRequest)> where M1.MatchedType == DAppAuthResponse, M2.MatchedType == DAppAuthRequest { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthResponse, DAppAuthRequest)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: request) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppAuthDelegate.self, method: "didReceiveAuthResponse(_: DAppAuthResponse, for: DAppAuthRequest)", parameterMatchers: matchers)) + func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?)> where M1.OptionalMatchedType == ExportGenericViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "close(view: ExportGenericViewProtocol?)", parameterMatchers: matchers)) + } + + func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", parameterMatchers: matchers)) + } + + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { + let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppAuthDelegate: Cuckoo.VerificationProxy { + struct __VerificationProxy_ExportRestoreJsonWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -15665,15 +14863,39 @@ import Cuckoo @discardableResult - func didReceiveAuthResponse(_ response: M1, for request: M2) -> Cuckoo.__DoNotUse<(DAppAuthResponse, DAppAuthRequest), Void> where M1.MatchedType == DAppAuthResponse, M2.MatchedType == DAppAuthRequest { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthResponse, DAppAuthRequest)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: request) { $0.1 }] - return cuckoo_manager.verify("didReceiveAuthResponse(_: DAppAuthResponse, for: DAppAuthRequest)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func close(view: M1) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(view: ExportGenericViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { + let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] + return cuckoo_manager.verify("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.__DoNotUse<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?), Void> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { + let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] + return cuckoo_manager.verify("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppAuthDelegateStub: DAppAuthDelegate { + class ExportRestoreJsonWireframeProtocolStub: ExportRestoreJsonWireframeProtocol { @@ -15681,7 +14903,31 @@ import Cuckoo - func didReceiveAuthResponse(_ response: DAppAuthResponse, for request: DAppAuthRequest) { + func close(view: ExportGenericViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -15692,22 +14938,21 @@ import Cuckoo @testable import novawallet import Foundation -import RobinHood - class MockDAppBrowserViewProtocol: DAppBrowserViewProtocol, Cuckoo.ProtocolMock { + class MockOnboardingMainViewProtocol: OnboardingMainViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppBrowserViewProtocol + typealias MocksType = OnboardingMainViewProtocol - typealias Stubbing = __StubbingProxy_DAppBrowserViewProtocol - typealias Verification = __VerificationProxy_DAppBrowserViewProtocol + typealias Stubbing = __StubbingProxy_OnboardingMainViewProtocol + typealias Verification = __VerificationProxy_OnboardingMainViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppBrowserViewProtocol? + private var __defaultImplStub: OnboardingMainViewProtocol? - func enableDefaultImplementation(_ stub: DAppBrowserViewProtocol) { + func enableDefaultImplementation(_ stub: OnboardingMainViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -15746,68 +14991,8 @@ import RobinHood - - - func didReceive(viewModel: DAppBrowserModel) { - - return cuckoo_manager.call("didReceive(viewModel: DAppBrowserModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) - - } - - - - func didReceive(response: DAppScriptResponse, forTransport name: String) { - - return cuckoo_manager.call("didReceive(response: DAppScriptResponse, forTransport: String)", - parameters: (response, name), - escapingParameters: (response, name), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(response: response, forTransport: name)) - - } - - - - func didReceiveReplacement(transports: [DAppTransportModel], postExecution script: DAppScriptResponse) { - - return cuckoo_manager.call("didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", - parameters: (transports, script), - escapingParameters: (transports, script), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveReplacement(transports: transports, postExecution: script)) - - } - - - - func didReceiveFavorite(flag: Bool) { - - return cuckoo_manager.call("didReceiveFavorite(flag: Bool)", - parameters: (flag), - escapingParameters: (flag), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFavorite(flag: flag)) - - } - - struct __StubbingProxy_DAppBrowserViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_OnboardingMainViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -15815,39 +15000,19 @@ import RobinHood } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserModel)> where M1.MatchedType == DAppBrowserModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserViewProtocol.self, method: "didReceive(viewModel: DAppBrowserModel)", parameterMatchers: matchers)) - } - - func didReceive(response: M1, forTransport name: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppScriptResponse, String)> where M1.MatchedType == DAppScriptResponse, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(DAppScriptResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserViewProtocol.self, method: "didReceive(response: DAppScriptResponse, forTransport: String)", parameterMatchers: matchers)) - } - - func didReceiveReplacement(transports: M1, postExecution script: M2) -> Cuckoo.ProtocolStubNoReturnFunction<([DAppTransportModel], DAppScriptResponse)> where M1.MatchedType == [DAppTransportModel], M2.MatchedType == DAppScriptResponse { - let matchers: [Cuckoo.ParameterMatcher<([DAppTransportModel], DAppScriptResponse)>] = [wrap(matchable: transports) { $0.0 }, wrap(matchable: script) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserViewProtocol.self, method: "didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", parameterMatchers: matchers)) - } - - func didReceiveFavorite(flag: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: flag) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserViewProtocol.self, method: "didReceiveFavorite(flag: Bool)", parameterMatchers: matchers)) - } - } - struct __VerificationProxy_DAppBrowserViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_OnboardingMainViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -15871,34 +15036,10 @@ import RobinHood - @discardableResult - func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(DAppBrowserModel), Void> where M1.MatchedType == DAppBrowserModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceive(viewModel: DAppBrowserModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(response: M1, forTransport name: M2) -> Cuckoo.__DoNotUse<(DAppScriptResponse, String), Void> where M1.MatchedType == DAppScriptResponse, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(DAppScriptResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] - return cuckoo_manager.verify("didReceive(response: DAppScriptResponse, forTransport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveReplacement(transports: M1, postExecution script: M2) -> Cuckoo.__DoNotUse<([DAppTransportModel], DAppScriptResponse), Void> where M1.MatchedType == [DAppTransportModel], M2.MatchedType == DAppScriptResponse { - let matchers: [Cuckoo.ParameterMatcher<([DAppTransportModel], DAppScriptResponse)>] = [wrap(matchable: transports) { $0.0 }, wrap(matchable: script) { $0.1 }] - return cuckoo_manager.verify("didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFavorite(flag: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: flag) { $0 }] - return cuckoo_manager.verify("didReceiveFavorite(flag: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } - class DAppBrowserViewProtocolStub: DAppBrowserViewProtocol { + class OnboardingMainViewProtocolStub: OnboardingMainViewProtocol { @@ -15922,47 +15063,23 @@ import RobinHood - - - func didReceive(viewModel: DAppBrowserModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(response: DAppScriptResponse, forTransport name: String) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveReplacement(transports: [DAppTransportModel], postExecution script: DAppScriptResponse) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFavorite(flag: Bool) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - } - class MockDAppBrowserPresenterProtocol: DAppBrowserPresenterProtocol, Cuckoo.ProtocolMock { + class MockOnboardingMainPresenterProtocol: OnboardingMainPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppBrowserPresenterProtocol + typealias MocksType = OnboardingMainPresenterProtocol - typealias Stubbing = __StubbingProxy_DAppBrowserPresenterProtocol - typealias Verification = __VerificationProxy_DAppBrowserPresenterProtocol + typealias Stubbing = __StubbingProxy_OnboardingMainPresenterProtocol + typealias Verification = __VerificationProxy_OnboardingMainPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppBrowserPresenterProtocol? + private var __defaultImplStub: OnboardingMainPresenterProtocol? - func enableDefaultImplementation(_ stub: DAppBrowserPresenterProtocol) { + func enableDefaultImplementation(_ stub: OnboardingMainPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -15990,81 +15107,96 @@ import RobinHood - func process(page: DAppBrowserPage) { + func activateSignup() { - return cuckoo_manager.call("process(page: DAppBrowserPage)", - parameters: (page), - escapingParameters: (page), + return cuckoo_manager.call("activateSignup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.process(page: page)) + defaultCall: __defaultImplStub!.activateSignup()) } - func process(message: Any, host: String, transport name: String) { + func activateAccountRestore() { - return cuckoo_manager.call("process(message: Any, host: String, transport: String)", - parameters: (message, host, name), - escapingParameters: (message, host, name), + return cuckoo_manager.call("activateAccountRestore()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.process(message: message, host: host, transport: name)) + defaultCall: __defaultImplStub!.activateAccountRestore()) } - func activateSearch(with query: String?) { + func activateWatchOnlyCreate() { - return cuckoo_manager.call("activateSearch(with: String?)", - parameters: (query), - escapingParameters: (query), + return cuckoo_manager.call("activateWatchOnlyCreate()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activateSearch(with: query)) + defaultCall: __defaultImplStub!.activateWatchOnlyCreate()) } - func toggleFavorite() { + func activateHardwareWalletCreate() { - return cuckoo_manager.call("toggleFavorite()", + return cuckoo_manager.call("activateHardwareWalletCreate()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.toggleFavorite()) + defaultCall: __defaultImplStub!.activateHardwareWalletCreate()) } - func close() { + func activateTerms() { - return cuckoo_manager.call("close()", + return cuckoo_manager.call("activateTerms()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close()) + defaultCall: __defaultImplStub!.activateTerms()) + + } + + + + func activatePrivacy() { + + return cuckoo_manager.call("activatePrivacy()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.activatePrivacy()) } - struct __StubbingProxy_DAppBrowserPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_OnboardingMainPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -16074,37 +15206,42 @@ import RobinHood func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func process(page: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserPage)> where M1.MatchedType == DAppBrowserPage { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserPage)>] = [wrap(matchable: page) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "process(page: DAppBrowserPage)", parameterMatchers: matchers)) + func activateSignup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateSignup()", parameterMatchers: matchers)) } - func process(message: M1, host: M2, transport name: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(Any, String, String)> where M1.MatchedType == Any, M2.MatchedType == String, M3.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(Any, String, String)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: host) { $0.1 }, wrap(matchable: name) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "process(message: Any, host: String, transport: String)", parameterMatchers: matchers)) + func activateAccountRestore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateAccountRestore()", parameterMatchers: matchers)) } - func activateSearch(with query: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: query) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "activateSearch(with: String?)", parameterMatchers: matchers)) + func activateWatchOnlyCreate() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateWatchOnlyCreate()", parameterMatchers: matchers)) } - func toggleFavorite() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func activateHardwareWalletCreate() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "toggleFavorite()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateHardwareWalletCreate()", parameterMatchers: matchers)) } - func close() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func activateTerms() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserPresenterProtocol.self, method: "close()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateTerms()", parameterMatchers: matchers)) + } + + func activatePrivacy() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activatePrivacy()", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppBrowserPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_OnboardingMainPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -16125,39 +15262,45 @@ import RobinHood } @discardableResult - func process(page: M1) -> Cuckoo.__DoNotUse<(DAppBrowserPage), Void> where M1.MatchedType == DAppBrowserPage { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserPage)>] = [wrap(matchable: page) { $0 }] - return cuckoo_manager.verify("process(page: DAppBrowserPage)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func activateSignup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("activateSignup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func process(message: M1, host: M2, transport name: M3) -> Cuckoo.__DoNotUse<(Any, String, String), Void> where M1.MatchedType == Any, M2.MatchedType == String, M3.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(Any, String, String)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: host) { $0.1 }, wrap(matchable: name) { $0.2 }] - return cuckoo_manager.verify("process(message: Any, host: String, transport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func activateAccountRestore() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("activateAccountRestore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func activateSearch(with query: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: query) { $0 }] - return cuckoo_manager.verify("activateSearch(with: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func activateWatchOnlyCreate() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("activateWatchOnlyCreate()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func toggleFavorite() -> Cuckoo.__DoNotUse<(), Void> { + func activateHardwareWalletCreate() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("toggleFavorite()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("activateHardwareWalletCreate()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func close() -> Cuckoo.__DoNotUse<(), Void> { + func activateTerms() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("close()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("activateTerms()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func activatePrivacy() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("activatePrivacy()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppBrowserPresenterProtocolStub: DAppBrowserPresenterProtocol { + class OnboardingMainPresenterProtocolStub: OnboardingMainPresenterProtocol { @@ -16171,31 +15314,37 @@ import RobinHood - func process(page: DAppBrowserPage) { + func activateSignup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func process(message: Any, host: String, transport name: String) { + func activateAccountRestore() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func activateSearch(with query: String?) { + func activateWatchOnlyCreate() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func toggleFavorite() { + func activateHardwareWalletCreate() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func close() { + func activateTerms() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func activatePrivacy() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -16203,19 +15352,19 @@ import RobinHood - class MockDAppBrowserInteractorInputProtocol: DAppBrowserInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockOnboardingMainWireframeProtocol: OnboardingMainWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppBrowserInteractorInputProtocol + typealias MocksType = OnboardingMainWireframeProtocol - typealias Stubbing = __StubbingProxy_DAppBrowserInteractorInputProtocol - typealias Verification = __VerificationProxy_DAppBrowserInteractorInputProtocol + typealias Stubbing = __StubbingProxy_OnboardingMainWireframeProtocol + typealias Verification = __VerificationProxy_OnboardingMainWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppBrowserInteractorInputProtocol? + private var __defaultImplStub: OnboardingMainWireframeProtocol? - func enableDefaultImplementation(_ stub: DAppBrowserInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: OnboardingMainWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -16228,126 +15377,141 @@ import RobinHood - func setup() { + func showSignup(from view: OnboardingMainViewProtocol?) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("showSignup(from: OnboardingMainViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.showSignup(from: view)) } - func process(host: String) { + func showAccountRestore(from view: OnboardingMainViewProtocol?) { - return cuckoo_manager.call("process(host: String)", - parameters: (host), - escapingParameters: (host), + return cuckoo_manager.call("showAccountRestore(from: OnboardingMainViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.process(host: host)) + defaultCall: __defaultImplStub!.showAccountRestore(from: view)) } - func process(message: Any, host: String, transport name: String) { + func showKeystoreImport(from view: OnboardingMainViewProtocol?) { - return cuckoo_manager.call("process(message: Any, host: String, transport: String)", - parameters: (message, host, name), - escapingParameters: (message, host, name), + return cuckoo_manager.call("showKeystoreImport(from: OnboardingMainViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.process(message: message, host: host, transport: name)) + defaultCall: __defaultImplStub!.showKeystoreImport(from: view)) } - func processConfirmation(response: DAppOperationResponse, forTransport name: String) { + func showWatchOnlyCreate(from view: OnboardingMainViewProtocol?) { - return cuckoo_manager.call("processConfirmation(response: DAppOperationResponse, forTransport: String)", - parameters: (response, name), - escapingParameters: (response, name), + return cuckoo_manager.call("showWatchOnlyCreate(from: OnboardingMainViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.processConfirmation(response: response, forTransport: name)) + defaultCall: __defaultImplStub!.showWatchOnlyCreate(from: view)) } - func process(newQuery: DAppSearchResult) { + func showParitySignerWalletCreation(from view: OnboardingMainViewProtocol?) { - return cuckoo_manager.call("process(newQuery: DAppSearchResult)", - parameters: (newQuery), - escapingParameters: (newQuery), + return cuckoo_manager.call("showParitySignerWalletCreation(from: OnboardingMainViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.process(newQuery: newQuery)) + defaultCall: __defaultImplStub!.showParitySignerWalletCreation(from: view)) } - func processAuth(response: DAppAuthResponse, forTransport name: String) { + func showLedgerWalletCreation(from view: OnboardingMainViewProtocol?) { - return cuckoo_manager.call("processAuth(response: DAppAuthResponse, forTransport: String)", - parameters: (response, name), - escapingParameters: (response, name), + return cuckoo_manager.call("showLedgerWalletCreation(from: OnboardingMainViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.processAuth(response: response, forTransport: name)) + defaultCall: __defaultImplStub!.showLedgerWalletCreation(from: view)) } - func removeFromFavorites(record: DAppFavorite) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - return cuckoo_manager.call("removeFromFavorites(record: DAppFavorite)", - parameters: (record), - escapingParameters: (record), + return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", + parameters: (url, view, style), + escapingParameters: (url, view, style), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.removeFromFavorites(record: record)) + defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) } - func reload() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("reload()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload()) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_DAppBrowserInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_OnboardingMainWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -16355,49 +15519,54 @@ import RobinHood } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + func showSignup(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showSignup(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) } - func process(host: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: host) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "process(host: String)", parameterMatchers: matchers)) + func showAccountRestore(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showAccountRestore(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) } - func process(message: M1, host: M2, transport name: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(Any, String, String)> where M1.MatchedType == Any, M2.MatchedType == String, M3.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(Any, String, String)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: host) { $0.1 }, wrap(matchable: name) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "process(message: Any, host: String, transport: String)", parameterMatchers: matchers)) + func showKeystoreImport(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showKeystoreImport(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) } - func processConfirmation(response: M1, forTransport name: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationResponse, String)> where M1.MatchedType == DAppOperationResponse, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "processConfirmation(response: DAppOperationResponse, forTransport: String)", parameterMatchers: matchers)) + func showWatchOnlyCreate(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showWatchOnlyCreate(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) } - func process(newQuery: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppSearchResult)> where M1.MatchedType == DAppSearchResult { - let matchers: [Cuckoo.ParameterMatcher<(DAppSearchResult)>] = [wrap(matchable: newQuery) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "process(newQuery: DAppSearchResult)", parameterMatchers: matchers)) + func showParitySignerWalletCreation(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showParitySignerWalletCreation(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) } - func processAuth(response: M1, forTransport name: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthResponse, String)> where M1.MatchedType == DAppAuthResponse, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "processAuth(response: DAppAuthResponse, forTransport: String)", parameterMatchers: matchers)) + func showLedgerWalletCreation(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showLedgerWalletCreation(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) } - func removeFromFavorites(record: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppFavorite)> where M1.MatchedType == DAppFavorite { - let matchers: [Cuckoo.ParameterMatcher<(DAppFavorite)>] = [wrap(matchable: record) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "removeFromFavorites(record: DAppFavorite)", parameterMatchers: matchers)) + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) } - func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorInputProtocol.self, method: "reload()", parameterMatchers: matchers)) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppBrowserInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_OnboardingMainWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -16412,57 +15581,63 @@ import RobinHood @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showSignup(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showSignup(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func process(host: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: host) { $0 }] - return cuckoo_manager.verify("process(host: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showAccountRestore(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showAccountRestore(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func process(message: M1, host: M2, transport name: M3) -> Cuckoo.__DoNotUse<(Any, String, String), Void> where M1.MatchedType == Any, M2.MatchedType == String, M3.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(Any, String, String)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: host) { $0.1 }, wrap(matchable: name) { $0.2 }] - return cuckoo_manager.verify("process(message: Any, host: String, transport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showKeystoreImport(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showKeystoreImport(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func processConfirmation(response: M1, forTransport name: M2) -> Cuckoo.__DoNotUse<(DAppOperationResponse, String), Void> where M1.MatchedType == DAppOperationResponse, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] - return cuckoo_manager.verify("processConfirmation(response: DAppOperationResponse, forTransport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showWatchOnlyCreate(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showWatchOnlyCreate(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func process(newQuery: M1) -> Cuckoo.__DoNotUse<(DAppSearchResult), Void> where M1.MatchedType == DAppSearchResult { - let matchers: [Cuckoo.ParameterMatcher<(DAppSearchResult)>] = [wrap(matchable: newQuery) { $0 }] - return cuckoo_manager.verify("process(newQuery: DAppSearchResult)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showParitySignerWalletCreation(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showParitySignerWalletCreation(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func processAuth(response: M1, forTransport name: M2) -> Cuckoo.__DoNotUse<(DAppAuthResponse, String), Void> where M1.MatchedType == DAppAuthResponse, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] - return cuckoo_manager.verify("processAuth(response: DAppAuthResponse, forTransport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showLedgerWalletCreation(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showLedgerWalletCreation(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func removeFromFavorites(record: M1) -> Cuckoo.__DoNotUse<(DAppFavorite), Void> where M1.MatchedType == DAppFavorite { - let matchers: [Cuckoo.ParameterMatcher<(DAppFavorite)>] = [wrap(matchable: record) { $0 }] - return cuckoo_manager.verify("removeFromFavorites(record: DAppFavorite)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func reload() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppBrowserInteractorInputProtocolStub: DAppBrowserInteractorInputProtocol { + class OnboardingMainWireframeProtocolStub: OnboardingMainWireframeProtocol { @@ -16470,49 +15645,55 @@ import RobinHood - func setup() { + func showSignup(from view: OnboardingMainViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func process(host: String) { + func showAccountRestore(from view: OnboardingMainViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func process(message: Any, host: String, transport name: String) { + func showKeystoreImport(from view: OnboardingMainViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func processConfirmation(response: DAppOperationResponse, forTransport name: String) { + func showWatchOnlyCreate(from view: OnboardingMainViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func process(newQuery: DAppSearchResult) { + func showParitySignerWalletCreation(from view: OnboardingMainViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func processAuth(response: DAppAuthResponse, forTransport name: String) { + func showLedgerWalletCreation(from view: OnboardingMainViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func removeFromFavorites(record: DAppFavorite) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func reload() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -16520,19 +15701,19 @@ import RobinHood - class MockDAppBrowserInteractorOutputProtocol: DAppBrowserInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockOnboardingMainInteractorInputProtocol: OnboardingMainInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppBrowserInteractorOutputProtocol + typealias MocksType = OnboardingMainInteractorInputProtocol - typealias Stubbing = __StubbingProxy_DAppBrowserInteractorOutputProtocol - typealias Verification = __VerificationProxy_DAppBrowserInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_OnboardingMainInteractorInputProtocol + typealias Verification = __VerificationProxy_OnboardingMainInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppBrowserInteractorOutputProtocol? + private var __defaultImplStub: OnboardingMainInteractorInputProtocol? - func enableDefaultImplementation(_ stub: DAppBrowserInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: OnboardingMainInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -16545,126 +15726,240 @@ import RobinHood - func didReceive(error: Error) { + func setup() { - return cuckoo_manager.call("didReceive(error: Error)", - parameters: (error), - escapingParameters: (error), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(error: error)) + defaultCall: __defaultImplStub!.setup()) } + + struct __StubbingProxy_OnboardingMainInteractorInputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_OnboardingMainInteractorInputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class OnboardingMainInteractorInputProtocolStub: OnboardingMainInteractorInputProtocol { + - func didReceiveDApp(model: DAppBrowserModel) { - - return cuckoo_manager.call("didReceiveDApp(model: DAppBrowserModel)", - parameters: (model), - escapingParameters: (model), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveDApp(model: model)) - + + + + + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockOnboardingMainInteractorOutputProtocol: OnboardingMainInteractorOutputProtocol, Cuckoo.ProtocolMock { + typealias MocksType = OnboardingMainInteractorOutputProtocol - func didReceiveReplacement(transports: [DAppTransportModel], postExecution script: DAppScriptResponse) { - - return cuckoo_manager.call("didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", - parameters: (transports, script), - escapingParameters: (transports, script), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveReplacement(transports: transports, postExecution: script)) - + typealias Stubbing = __StubbingProxy_OnboardingMainInteractorOutputProtocol + typealias Verification = __VerificationProxy_OnboardingMainInteractorOutputProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: OnboardingMainInteractorOutputProtocol? + + func enableDefaultImplementation(_ stub: OnboardingMainInteractorOutputProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + + + - func didReceive(response: DAppScriptResponse, forTransport name: String) { + + + func didSuggestKeystoreImport() { - return cuckoo_manager.call("didReceive(response: DAppScriptResponse, forTransport: String)", - parameters: (response, name), - escapingParameters: (response, name), + return cuckoo_manager.call("didSuggestKeystoreImport()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(response: response, forTransport: name)) + defaultCall: __defaultImplStub!.didSuggestKeystoreImport()) } - - - func didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType) { - - return cuckoo_manager.call("didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType)", - parameters: (request, type), - escapingParameters: (request, type), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveConfirmation(request: request, type: type)) - + + struct __StubbingProxy_OnboardingMainInteractorOutputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func didSuggestKeystoreImport() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainInteractorOutputProtocol.self, method: "didSuggestKeystoreImport()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_OnboardingMainInteractorOutputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func didSuggestKeystoreImport() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didSuggestKeystoreImport()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class OnboardingMainInteractorOutputProtocolStub: OnboardingMainInteractorOutputProtocol { + + + + + + + + func didSuggestKeystoreImport() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + +import Cuckoo +@testable import novawallet + +import CommonWallet + + + class MockOperationDetailsViewProtocol: OperationDetailsViewProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = OperationDetailsViewProtocol + + typealias Stubbing = __StubbingProxy_OperationDetailsViewProtocol + typealias Verification = __VerificationProxy_OperationDetailsViewProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: OperationDetailsViewProtocol? + + func enableDefaultImplementation(_ stub: OperationDetailsViewProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + - func didReceiveAuth(request: DAppAuthRequest) { - - return cuckoo_manager.call("didReceiveAuth(request: DAppAuthRequest)", - parameters: (request), - escapingParameters: (request), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAuth(request: request)) + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } } - func didDetectPhishing(host: String) { - - return cuckoo_manager.call("didDetectPhishing(host: String)", - parameters: (host), - escapingParameters: (host), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didDetectPhishing(host: host)) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } + + + + - func didReceiveFavorite(changes: [DataProviderChange]) { + func didReceive(viewModel: OperationDetailsViewModel) { - return cuckoo_manager.call("didReceiveFavorite(changes: [DataProviderChange])", - parameters: (changes), - escapingParameters: (changes), + return cuckoo_manager.call("didReceive(viewModel: OperationDetailsViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFavorite(changes: changes)) + defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) } - struct __StubbingProxy_DAppBrowserInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_OperationDetailsViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -16672,49 +15967,24 @@ import RobinHood } - func didReceive(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceive(error: Error)", parameterMatchers: matchers)) - } - - func didReceiveDApp(model: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserModel)> where M1.MatchedType == DAppBrowserModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserModel)>] = [wrap(matchable: model) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveDApp(model: DAppBrowserModel)", parameterMatchers: matchers)) - } - - func didReceiveReplacement(transports: M1, postExecution script: M2) -> Cuckoo.ProtocolStubNoReturnFunction<([DAppTransportModel], DAppScriptResponse)> where M1.MatchedType == [DAppTransportModel], M2.MatchedType == DAppScriptResponse { - let matchers: [Cuckoo.ParameterMatcher<([DAppTransportModel], DAppScriptResponse)>] = [wrap(matchable: transports) { $0.0 }, wrap(matchable: script) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", parameterMatchers: matchers)) - } - - func didReceive(response: M1, forTransport name: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppScriptResponse, String)> where M1.MatchedType == DAppScriptResponse, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(DAppScriptResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceive(response: DAppScriptResponse, forTransport: String)", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func didReceiveConfirmation(request: M1, type: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationRequest, DAppSigningType)> where M1.MatchedType == DAppOperationRequest, M2.MatchedType == DAppSigningType { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationRequest, DAppSigningType)>] = [wrap(matchable: request) { $0.0 }, wrap(matchable: type) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType)", parameterMatchers: matchers)) - } - func didReceiveAuth(request: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppAuthRequest)> where M1.MatchedType == DAppAuthRequest { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthRequest)>] = [wrap(matchable: request) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveAuth(request: DAppAuthRequest)", parameterMatchers: matchers)) + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func didDetectPhishing(host: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: host) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didDetectPhishing(host: String)", parameterMatchers: matchers)) - } - func didReceiveFavorite(changes: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([DataProviderChange])> where M1.MatchedType == [DataProviderChange] { - let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserInteractorOutputProtocol.self, method: "didReceiveFavorite(changes: [DataProviderChange])", parameterMatchers: matchers)) + func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OperationDetailsViewModel)> where M1.MatchedType == OperationDetailsViewModel { + let matchers: [Cuckoo.ParameterMatcher<(OperationDetailsViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsViewProtocol.self, method: "didReceive(viewModel: OperationDetailsViewModel)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppBrowserInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_OperationDetailsViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -16726,110 +15996,54 @@ import RobinHood } - - - @discardableResult - func didReceive(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return cuckoo_manager.verify("didReceive(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveDApp(model: M1) -> Cuckoo.__DoNotUse<(DAppBrowserModel), Void> where M1.MatchedType == DAppBrowserModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserModel)>] = [wrap(matchable: model) { $0 }] - return cuckoo_manager.verify("didReceiveDApp(model: DAppBrowserModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveReplacement(transports: M1, postExecution script: M2) -> Cuckoo.__DoNotUse<([DAppTransportModel], DAppScriptResponse), Void> where M1.MatchedType == [DAppTransportModel], M2.MatchedType == DAppScriptResponse { - let matchers: [Cuckoo.ParameterMatcher<([DAppTransportModel], DAppScriptResponse)>] = [wrap(matchable: transports) { $0.0 }, wrap(matchable: script) { $0.1 }] - return cuckoo_manager.verify("didReceiveReplacement(transports: [DAppTransportModel], postExecution: DAppScriptResponse)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - @discardableResult - func didReceive(response: M1, forTransport name: M2) -> Cuckoo.__DoNotUse<(DAppScriptResponse, String), Void> where M1.MatchedType == DAppScriptResponse, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(DAppScriptResponse, String)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: name) { $0.1 }] - return cuckoo_manager.verify("didReceive(response: DAppScriptResponse, forTransport: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceiveConfirmation(request: M1, type: M2) -> Cuckoo.__DoNotUse<(DAppOperationRequest, DAppSigningType), Void> where M1.MatchedType == DAppOperationRequest, M2.MatchedType == DAppSigningType { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationRequest, DAppSigningType)>] = [wrap(matchable: request) { $0.0 }, wrap(matchable: type) { $0.1 }] - return cuckoo_manager.verify("didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveAuth(request: M1) -> Cuckoo.__DoNotUse<(DAppAuthRequest), Void> where M1.MatchedType == DAppAuthRequest { - let matchers: [Cuckoo.ParameterMatcher<(DAppAuthRequest)>] = [wrap(matchable: request) { $0 }] - return cuckoo_manager.verify("didReceiveAuth(request: DAppAuthRequest)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didDetectPhishing(host: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: host) { $0 }] - return cuckoo_manager.verify("didDetectPhishing(host: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } + @discardableResult - func didReceiveFavorite(changes: M1) -> Cuckoo.__DoNotUse<([DataProviderChange]), Void> where M1.MatchedType == [DataProviderChange] { - let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] - return cuckoo_manager.verify("didReceiveFavorite(changes: [DataProviderChange])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(OperationDetailsViewModel), Void> where M1.MatchedType == OperationDetailsViewModel { + let matchers: [Cuckoo.ParameterMatcher<(OperationDetailsViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceive(viewModel: OperationDetailsViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppBrowserInteractorOutputProtocolStub: DAppBrowserInteractorOutputProtocol { - - - - - - - - func didReceive(error: Error) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveDApp(model: DAppBrowserModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveReplacement(transports: [DAppTransportModel], postExecution script: DAppScriptResponse) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(response: DAppScriptResponse, forTransport name: String) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - + class OperationDetailsViewProtocolStub: OperationDetailsViewProtocol { + - func didReceiveConfirmation(request: DAppOperationRequest, type: DAppSigningType) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + } + - - func didReceiveAuth(request: DAppAuthRequest) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + - - func didDetectPhishing(host: String) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceiveFavorite(changes: [DataProviderChange]) { + func didReceive(viewModel: OperationDetailsViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -16837,19 +16051,19 @@ import RobinHood - class MockDAppBrowserWireframeProtocol: DAppBrowserWireframeProtocol, Cuckoo.ProtocolMock { + class MockOperationDetailsPresenterProtocol: OperationDetailsPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppBrowserWireframeProtocol + typealias MocksType = OperationDetailsPresenterProtocol - typealias Stubbing = __StubbingProxy_DAppBrowserWireframeProtocol - typealias Verification = __VerificationProxy_DAppBrowserWireframeProtocol + typealias Stubbing = __StubbingProxy_OperationDetailsPresenterProtocol + typealias Verification = __VerificationProxy_OperationDetailsPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppBrowserWireframeProtocol? + private var __defaultImplStub: OperationDetailsPresenterProtocol? - func enableDefaultImplementation(_ stub: DAppBrowserWireframeProtocol) { + func enableDefaultImplementation(_ stub: OperationDetailsPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -16862,96 +16076,81 @@ import RobinHood - func presentOperationConfirm(from view: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate) { - - return cuckoo_manager.call("presentOperationConfirm(from: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate)", - parameters: (view, request, type, delegate), - escapingParameters: (view, request, type, delegate), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.presentOperationConfirm(from: view, request: request, type: type, delegate: delegate)) - - } - - - - func presentSearch(from view: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate) { + func setup() { - return cuckoo_manager.call("presentSearch(from: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate)", - parameters: (view, initialQuery, delegate), - escapingParameters: (view, initialQuery, delegate), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentSearch(from: view, initialQuery: initialQuery, delegate: delegate)) + defaultCall: __defaultImplStub!.setup()) } - func presentAuth(from view: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate) { + func showSenderActions() { - return cuckoo_manager.call("presentAuth(from: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate)", - parameters: (view, request, delegate), - escapingParameters: (view, request, delegate), + return cuckoo_manager.call("showSenderActions()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentAuth(from: view, request: request, delegate: delegate)) + defaultCall: __defaultImplStub!.showSenderActions()) } - func presentPhishingDetected(from view: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate) { + func showRecepientActions() { - return cuckoo_manager.call("presentPhishingDetected(from: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate)", - parameters: (view, delegate), - escapingParameters: (view, delegate), + return cuckoo_manager.call("showRecepientActions()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentPhishingDetected(from: view, delegate: delegate)) + defaultCall: __defaultImplStub!.showRecepientActions()) } - func presentAddToFavoriteForm(from view: DAppBrowserViewProtocol?, page: DAppBrowserPage) { + func showOperationActions() { - return cuckoo_manager.call("presentAddToFavoriteForm(from: DAppBrowserViewProtocol?, page: DAppBrowserPage)", - parameters: (view, page), - escapingParameters: (view, page), + return cuckoo_manager.call("showOperationActions()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentAddToFavoriteForm(from: view, page: page)) + defaultCall: __defaultImplStub!.showOperationActions()) } - func close(view: DAppBrowserViewProtocol?) { + func send() { - return cuckoo_manager.call("close(view: DAppBrowserViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("send()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(view: view)) + defaultCall: __defaultImplStub!.send()) } - struct __StubbingProxy_DAppBrowserWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_OperationDetailsPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -16959,39 +16158,34 @@ import RobinHood } - func presentOperationConfirm(from view: M1, request: M2, type: M3, delegate: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, DAppOperationRequest, DAppSigningType, DAppOperationConfirmDelegate)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppOperationRequest, M3.MatchedType == DAppSigningType, M4.MatchedType == DAppOperationConfirmDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppOperationRequest, DAppSigningType, DAppOperationConfirmDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: request) { $0.1 }, wrap(matchable: type) { $0.2 }, wrap(matchable: delegate) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentOperationConfirm(from: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate)", parameterMatchers: matchers)) - } - - func presentSearch(from view: M1, initialQuery: M2, delegate: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, String?, DAppSearchDelegate)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.OptionalMatchedType == String, M3.MatchedType == DAppSearchDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, String?, DAppSearchDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: initialQuery) { $0.1 }, wrap(matchable: delegate) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentSearch(from: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func presentAuth(from view: M1, request: M2, delegate: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, DAppAuthRequest, DAppAuthDelegate)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppAuthRequest, M3.MatchedType == DAppAuthDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppAuthRequest, DAppAuthDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: request) { $0.1 }, wrap(matchable: delegate) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentAuth(from: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate)", parameterMatchers: matchers)) + func showSenderActions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "showSenderActions()", parameterMatchers: matchers)) } - func presentPhishingDetected(from view: M1, delegate: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, DAppPhishingViewDelegate)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppPhishingViewDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppPhishingViewDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentPhishingDetected(from: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate)", parameterMatchers: matchers)) + func showRecepientActions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "showRecepientActions()", parameterMatchers: matchers)) } - func presentAddToFavoriteForm(from view: M1, page: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?, DAppBrowserPage)> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppBrowserPage { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppBrowserPage)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: page) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "presentAddToFavoriteForm(from: DAppBrowserViewProtocol?, page: DAppBrowserPage)", parameterMatchers: matchers)) + func showOperationActions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "showOperationActions()", parameterMatchers: matchers)) } - func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppBrowserViewProtocol?)> where M1.OptionalMatchedType == DAppBrowserViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppBrowserWireframeProtocol.self, method: "close(view: DAppBrowserViewProtocol?)", parameterMatchers: matchers)) + func send() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "send()", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppBrowserWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_OperationDetailsPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -17006,45 +16200,39 @@ import RobinHood @discardableResult - func presentOperationConfirm(from view: M1, request: M2, type: M3, delegate: M4) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, DAppOperationRequest, DAppSigningType, DAppOperationConfirmDelegate), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppOperationRequest, M3.MatchedType == DAppSigningType, M4.MatchedType == DAppOperationConfirmDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppOperationRequest, DAppSigningType, DAppOperationConfirmDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: request) { $0.1 }, wrap(matchable: type) { $0.2 }, wrap(matchable: delegate) { $0.3 }] - return cuckoo_manager.verify("presentOperationConfirm(from: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func presentSearch(from view: M1, initialQuery: M2, delegate: M3) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, String?, DAppSearchDelegate), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.OptionalMatchedType == String, M3.MatchedType == DAppSearchDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, String?, DAppSearchDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: initialQuery) { $0.1 }, wrap(matchable: delegate) { $0.2 }] - return cuckoo_manager.verify("presentSearch(from: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentAuth(from view: M1, request: M2, delegate: M3) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, DAppAuthRequest, DAppAuthDelegate), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppAuthRequest, M3.MatchedType == DAppAuthDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppAuthRequest, DAppAuthDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: request) { $0.1 }, wrap(matchable: delegate) { $0.2 }] - return cuckoo_manager.verify("presentAuth(from: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showSenderActions() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("showSenderActions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentPhishingDetected(from view: M1, delegate: M2) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, DAppPhishingViewDelegate), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppPhishingViewDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppPhishingViewDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }] - return cuckoo_manager.verify("presentPhishingDetected(from: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showRecepientActions() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("showRecepientActions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentAddToFavoriteForm(from view: M1, page: M2) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?, DAppBrowserPage), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol, M2.MatchedType == DAppBrowserPage { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?, DAppBrowserPage)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: page) { $0.1 }] - return cuckoo_manager.verify("presentAddToFavoriteForm(from: DAppBrowserViewProtocol?, page: DAppBrowserPage)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showOperationActions() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("showOperationActions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func close(view: M1) -> Cuckoo.__DoNotUse<(DAppBrowserViewProtocol?), Void> where M1.OptionalMatchedType == DAppBrowserViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppBrowserViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(view: DAppBrowserViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func send() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("send()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppBrowserWireframeProtocolStub: DAppBrowserWireframeProtocol { + class OperationDetailsPresenterProtocolStub: OperationDetailsPresenterProtocol { @@ -17052,148 +16240,78 @@ import RobinHood - func presentOperationConfirm(from view: DAppBrowserViewProtocol?, request: DAppOperationRequest, type: DAppSigningType, delegate: DAppOperationConfirmDelegate) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func presentSearch(from view: DAppBrowserViewProtocol?, initialQuery: String?, delegate: DAppSearchDelegate) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentAuth(from view: DAppBrowserViewProtocol?, request: DAppAuthRequest, delegate: DAppAuthDelegate) { + func showSenderActions() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentPhishingDetected(from view: DAppBrowserViewProtocol?, delegate: DAppPhishingViewDelegate) { + func showRecepientActions() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentAddToFavoriteForm(from view: DAppBrowserViewProtocol?, page: DAppBrowserPage) { + func showOperationActions() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func close(view: DAppBrowserViewProtocol?) { + func send() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import RobinHood -import SubstrateSdk - - class MockDAppListViewProtocol: DAppListViewProtocol, Cuckoo.ProtocolMock { + class MockOperationDetailsInteractorInputProtocol: OperationDetailsInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppListViewProtocol + typealias MocksType = OperationDetailsInteractorInputProtocol - typealias Stubbing = __StubbingProxy_DAppListViewProtocol - typealias Verification = __VerificationProxy_DAppListViewProtocol + typealias Stubbing = __StubbingProxy_OperationDetailsInteractorInputProtocol + typealias Verification = __VerificationProxy_OperationDetailsInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppListViewProtocol? + private var __defaultImplStub: OperationDetailsInteractorInputProtocol? - func enableDefaultImplementation(_ stub: DAppListViewProtocol) { + func enableDefaultImplementation(_ stub: OperationDetailsInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - func didReceiveWalletSwitch(viewModel: WalletSwitchViewModel) { + func setup() { - return cuckoo_manager.call("didReceiveWalletSwitch(viewModel: WalletSwitchViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveWalletSwitch(viewModel: viewModel)) - - } - - - - func didReceive(state: DAppListState) { - - return cuckoo_manager.call("didReceive(state: DAppListState)", - parameters: (state), - escapingParameters: (state), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(state: state)) - - } - - - - func didCompleteRefreshing() { - - return cuckoo_manager.call("didCompleteRefreshing()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didCompleteRefreshing()) + defaultCall: __defaultImplStub!.setup()) } - struct __StubbingProxy_DAppListViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_OperationDetailsInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -17201,34 +16319,14 @@ import SubstrateSdk } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - func didReceiveWalletSwitch(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(WalletSwitchViewModel)> where M1.MatchedType == WalletSwitchViewModel { - let matchers: [Cuckoo.ParameterMatcher<(WalletSwitchViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListViewProtocol.self, method: "didReceiveWalletSwitch(viewModel: WalletSwitchViewModel)", parameterMatchers: matchers)) - } - - func didReceive(state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppListState)> where M1.MatchedType == DAppListState { - let matchers: [Cuckoo.ParameterMatcher<(DAppListState)>] = [wrap(matchable: state) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListViewProtocol.self, method: "didReceive(state: DAppListState)", parameterMatchers: matchers)) - } - - func didCompleteRefreshing() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListViewProtocol.self, method: "didCompleteRefreshing()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppListViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_OperationDetailsInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -17240,78 +16338,119 @@ import SubstrateSdk } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveWalletSwitch(viewModel: M1) -> Cuckoo.__DoNotUse<(WalletSwitchViewModel), Void> where M1.MatchedType == WalletSwitchViewModel { - let matchers: [Cuckoo.ParameterMatcher<(WalletSwitchViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveWalletSwitch(viewModel: WalletSwitchViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(state: M1) -> Cuckoo.__DoNotUse<(DAppListState), Void> where M1.MatchedType == DAppListState { - let matchers: [Cuckoo.ParameterMatcher<(DAppListState)>] = [wrap(matchable: state) { $0 }] - return cuckoo_manager.verify("didReceive(state: DAppListState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didCompleteRefreshing() -> Cuckoo.__DoNotUse<(), Void> { + func setup() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didCompleteRefreshing()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppListViewProtocolStub: DAppListViewProtocol { - + class OperationDetailsInteractorInputProtocolStub: OperationDetailsInteractorInputProtocol { + - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + + + + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - +} + + + + class MockOperationDetailsInteractorOutputProtocol: OperationDetailsInteractorOutputProtocol, Cuckoo.ProtocolMock { - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - + typealias MocksType = OperationDetailsInteractorOutputProtocol + + typealias Stubbing = __StubbingProxy_OperationDetailsInteractorOutputProtocol + typealias Verification = __VerificationProxy_OperationDetailsInteractorOutputProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: OperationDetailsInteractorOutputProtocol? + + func enableDefaultImplementation(_ stub: OperationDetailsInteractorOutputProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + - func didReceiveWalletSwitch(viewModel: WalletSwitchViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + + func didReceiveDetails(result: Result) { + + return cuckoo_manager.call("didReceiveDetails(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveDetails(result: result)) + } + + struct __StubbingProxy_OperationDetailsInteractorOutputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func didReceiveDetails(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsInteractorOutputProtocol.self, method: "didReceiveDetails(result: Result)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_OperationDetailsInteractorOutputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func didReceiveDetails(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveDetails(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class OperationDetailsInteractorOutputProtocolStub: OperationDetailsInteractorOutputProtocol { + - func didReceive(state: DAppListState) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didCompleteRefreshing() { + func didReceiveDetails(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -17319,19 +16458,19 @@ import SubstrateSdk - class MockDAppListPresenterProtocol: DAppListPresenterProtocol, Cuckoo.ProtocolMock { + class MockOperationDetailsWireframeProtocol: OperationDetailsWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppListPresenterProtocol + typealias MocksType = OperationDetailsWireframeProtocol - typealias Stubbing = __StubbingProxy_DAppListPresenterProtocol - typealias Verification = __VerificationProxy_DAppListPresenterProtocol + typealias Stubbing = __StubbingProxy_OperationDetailsWireframeProtocol + typealias Verification = __VerificationProxy_OperationDetailsWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppListPresenterProtocol? + private var __defaultImplStub: OperationDetailsWireframeProtocol? - func enableDefaultImplementation(_ stub: DAppListPresenterProtocol) { + func enableDefaultImplementation(_ stub: OperationDetailsWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -17344,201 +16483,241 @@ import SubstrateSdk - func setup() { + func showSend(from view: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("showSend(from: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset)", + parameters: (view, displayAddress, chainAsset), + escapingParameters: (view, displayAddress, chainAsset), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.showSend(from: view, displayAddress: displayAddress, chainAsset: chainAsset)) } - func refresh() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("refresh()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.refresh()) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - func activateAccount() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("activateAccount()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activateAccount()) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } + + struct __StubbingProxy_OperationDetailsWireframeProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func showSend(from view: M1, displayAddress: M2, chainAsset: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(OperationDetailsViewProtocol?, DisplayAddress, ChainAsset)> where M1.OptionalMatchedType == OperationDetailsViewProtocol, M2.MatchedType == DisplayAddress, M3.MatchedType == ChainAsset { + let matchers: [Cuckoo.ParameterMatcher<(OperationDetailsViewProtocol?, DisplayAddress, ChainAsset)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: displayAddress) { $0.1 }, wrap(matchable: chainAsset) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsWireframeProtocol.self, method: "showSend(from: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset)", parameterMatchers: matchers)) + } + + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_OperationDetailsWireframeProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func showSend(from view: M1, displayAddress: M2, chainAsset: M3) -> Cuckoo.__DoNotUse<(OperationDetailsViewProtocol?, DisplayAddress, ChainAsset), Void> where M1.OptionalMatchedType == OperationDetailsViewProtocol, M2.MatchedType == DisplayAddress, M3.MatchedType == ChainAsset { + let matchers: [Cuckoo.ParameterMatcher<(OperationDetailsViewProtocol?, DisplayAddress, ChainAsset)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: displayAddress) { $0.1 }, wrap(matchable: chainAsset) { $0.2 }] + return cuckoo_manager.verify("showSend(from: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class OperationDetailsWireframeProtocolStub: OperationDetailsWireframeProtocol { + - func activateSearch() { - - return cuckoo_manager.call("activateSearch()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.activateSearch()) - - } + - func activateSettings() { - - return cuckoo_manager.call("activateSettings()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.activateSettings()) - + func showSend(from view: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func numberOfCategories() -> Int { - - return cuckoo_manager.call("numberOfCategories() -> Int", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.numberOfCategories()) - + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func category(at index: Int) -> String { - - return cuckoo_manager.call("category(at: Int) -> String", - parameters: (index), - escapingParameters: (index), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.category(at: index)) - + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + +import Cuckoo +@testable import novawallet + +import UIKit + + + class MockPinSetupViewProtocol: PinSetupViewProtocol, Cuckoo.ProtocolMock { + typealias MocksType = PinSetupViewProtocol - func selectedCategoryIndex() -> Int { - - return cuckoo_manager.call("selectedCategoryIndex() -> Int", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.selectedCategoryIndex()) - + typealias Stubbing = __StubbingProxy_PinSetupViewProtocol + typealias Verification = __VerificationProxy_PinSetupViewProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: PinSetupViewProtocol? + + func enableDefaultImplementation(_ stub: PinSetupViewProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + - func selectCategory(at index: Int) { - - return cuckoo_manager.call("selectCategory(at: Int)", - parameters: (index), - escapingParameters: (index), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.selectCategory(at: index)) + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } } - func numberOfDApps() -> Int { - - return cuckoo_manager.call("numberOfDApps() -> Int", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.numberOfDApps()) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } + + - func dApp(at index: Int) -> DAppViewModel { + + + func didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void) { - return cuckoo_manager.call("dApp(at: Int) -> DAppViewModel", - parameters: (index), - escapingParameters: (index), + return cuckoo_manager.call("didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", + parameters: (biometryType, completionBlock), + escapingParameters: (biometryType, completionBlock), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.dApp(at: index)) + defaultCall: __defaultImplStub!.didRequestBiometryUsage(biometryType: biometryType, completionBlock: completionBlock)) } - func selectDApp(at index: Int) { + func didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType) { - return cuckoo_manager.call("selectDApp(at: Int)", - parameters: (index), - escapingParameters: (index), + return cuckoo_manager.call("didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType)", + parameters: (enabled, availableBiometryType), + escapingParameters: (enabled, availableBiometryType), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectDApp(at: index)) + defaultCall: __defaultImplStub!.didChangeAccessoryState(enabled: enabled, availableBiometryType: availableBiometryType)) } - func toogleFavoriteForDApp(at index: Int) { + func didReceiveWrongPincode() { - return cuckoo_manager.call("toogleFavoriteForDApp(at: Int)", - parameters: (index), - escapingParameters: (index), + return cuckoo_manager.call("didReceiveWrongPincode()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.toogleFavoriteForDApp(at: index)) + defaultCall: __defaultImplStub!.didReceiveWrongPincode()) } - struct __StubbingProxy_DAppListPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_PinSetupViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -17546,249 +16725,117 @@ import SubstrateSdk } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func refresh() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "refresh()", parameterMatchers: matchers)) - } - func activateAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "activateAccount()", parameterMatchers: matchers)) + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func activateSearch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "activateSearch()", parameterMatchers: matchers)) + + func didRequestBiometryUsage(biometryType: M1, completionBlock: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(AvailableBiometryType, (Bool) -> Void)> where M1.MatchedType == AvailableBiometryType, M2.MatchedType == (Bool) -> Void { + let matchers: [Cuckoo.ParameterMatcher<(AvailableBiometryType, (Bool) -> Void)>] = [wrap(matchable: biometryType) { $0.0 }, wrap(matchable: completionBlock) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupViewProtocol.self, method: "didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", parameterMatchers: matchers)) } - func activateSettings() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "activateSettings()", parameterMatchers: matchers)) + func didChangeAccessoryState(enabled: M1, availableBiometryType: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool, AvailableBiometryType)> where M1.MatchedType == Bool, M2.MatchedType == AvailableBiometryType { + let matchers: [Cuckoo.ParameterMatcher<(Bool, AvailableBiometryType)>] = [wrap(matchable: enabled) { $0.0 }, wrap(matchable: availableBiometryType) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupViewProtocol.self, method: "didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType)", parameterMatchers: matchers)) } - func numberOfCategories() -> Cuckoo.ProtocolStubFunction<(), Int> { + func didReceiveWrongPincode() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "numberOfCategories() -> Int", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupViewProtocol.self, method: "didReceiveWrongPincode()", parameterMatchers: matchers)) } - func category(at index: M1) -> Cuckoo.ProtocolStubFunction<(Int), String> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "category(at: Int) -> String", parameterMatchers: matchers)) + } + + struct __VerificationProxy_PinSetupViewProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation } + - func selectedCategoryIndex() -> Cuckoo.ProtocolStubFunction<(), Int> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "selectedCategoryIndex() -> Int", parameterMatchers: matchers)) - } - func selectCategory(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "selectCategory(at: Int)", parameterMatchers: matchers)) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) } - func numberOfDApps() -> Cuckoo.ProtocolStubFunction<(), Int> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "numberOfDApps() -> Int", parameterMatchers: matchers)) + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - func dApp(at index: M1) -> Cuckoo.ProtocolStubFunction<(Int), DAppViewModel> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "dApp(at: Int) -> DAppViewModel", parameterMatchers: matchers)) - } - - func selectDApp(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "selectDApp(at: Int)", parameterMatchers: matchers)) - } - - func toogleFavoriteForDApp(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListPresenterProtocol.self, method: "toogleFavoriteForDApp(at: Int)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_DAppListPresenterProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func refresh() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("refresh()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func activateAccount() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func activateSearch() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateSearch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func activateSettings() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateSettings()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func numberOfCategories() -> Cuckoo.__DoNotUse<(), Int> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("numberOfCategories() -> Int", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func category(at index: M1) -> Cuckoo.__DoNotUse<(Int), String> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("category(at: Int) -> String", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func selectedCategoryIndex() -> Cuckoo.__DoNotUse<(), Int> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectedCategoryIndex() -> Int", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didRequestBiometryUsage(biometryType: M1, completionBlock: M2) -> Cuckoo.__DoNotUse<(AvailableBiometryType, (Bool) -> Void), Void> where M1.MatchedType == AvailableBiometryType, M2.MatchedType == (Bool) -> Void { + let matchers: [Cuckoo.ParameterMatcher<(AvailableBiometryType, (Bool) -> Void)>] = [wrap(matchable: biometryType) { $0.0 }, wrap(matchable: completionBlock) { $0.1 }] + return cuckoo_manager.verify("didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectCategory(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("selectCategory(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didChangeAccessoryState(enabled: M1, availableBiometryType: M2) -> Cuckoo.__DoNotUse<(Bool, AvailableBiometryType), Void> where M1.MatchedType == Bool, M2.MatchedType == AvailableBiometryType { + let matchers: [Cuckoo.ParameterMatcher<(Bool, AvailableBiometryType)>] = [wrap(matchable: enabled) { $0.0 }, wrap(matchable: availableBiometryType) { $0.1 }] + return cuckoo_manager.verify("didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func numberOfDApps() -> Cuckoo.__DoNotUse<(), Int> { + func didReceiveWrongPincode() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("numberOfDApps() -> Int", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func dApp(at index: M1) -> Cuckoo.__DoNotUse<(Int), DAppViewModel> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("dApp(at: Int) -> DAppViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func selectDApp(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("selectDApp(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func toogleFavoriteForDApp(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("toogleFavoriteForDApp(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("didReceiveWrongPincode()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppListPresenterProtocolStub: DAppListPresenterProtocol { - - - - - - - - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func refresh() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func activateAccount() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func activateSearch() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func activateSettings() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - + class PinSetupViewProtocolStub: PinSetupViewProtocol { + - func numberOfCategories() -> Int { - return DefaultValueRegistry.defaultValue(for: (Int).self) + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + } + - - func category(at index: Int) -> String { - return DefaultValueRegistry.defaultValue(for: (String).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + - - func selectedCategoryIndex() -> Int { - return DefaultValueRegistry.defaultValue(for: (Int).self) - } + - func selectCategory(at index: Int) { + func didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func numberOfDApps() -> Int { - return DefaultValueRegistry.defaultValue(for: (Int).self) - } - - - - func dApp(at index: Int) -> DAppViewModel { - return DefaultValueRegistry.defaultValue(for: (DAppViewModel).self) - } - - - - func selectDApp(at index: Int) { + func didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func toogleFavoriteForDApp(at index: Int) { + func didReceiveWrongPincode() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -17796,19 +16843,19 @@ import SubstrateSdk - class MockDAppListInteractorInputProtocol: DAppListInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockPinSetupPresenterProtocol: PinSetupPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppListInteractorInputProtocol + typealias MocksType = PinSetupPresenterProtocol - typealias Stubbing = __StubbingProxy_DAppListInteractorInputProtocol - typealias Verification = __VerificationProxy_DAppListInteractorInputProtocol + typealias Stubbing = __StubbingProxy_PinSetupPresenterProtocol + typealias Verification = __VerificationProxy_PinSetupPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppListInteractorInputProtocol? + private var __defaultImplStub: PinSetupPresenterProtocol? - func enableDefaultImplementation(_ stub: DAppListInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: PinSetupPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -17821,66 +16868,66 @@ import SubstrateSdk - func setup() { + func start() { - return cuckoo_manager.call("setup()", + return cuckoo_manager.call("start()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.start()) } - func refresh() { + func cancel() { - return cuckoo_manager.call("refresh()", + return cuckoo_manager.call("cancel()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.refresh()) + defaultCall: __defaultImplStub!.cancel()) } - func addToFavorites(dApp: DApp) { + func activateBiometricAuth() { - return cuckoo_manager.call("addToFavorites(dApp: DApp)", - parameters: (dApp), - escapingParameters: (dApp), + return cuckoo_manager.call("activateBiometricAuth()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.addToFavorites(dApp: dApp)) + defaultCall: __defaultImplStub!.activateBiometricAuth()) } - func removeFromFavorites(dAppIdentifier: String) { + func submit(pin: String) { - return cuckoo_manager.call("removeFromFavorites(dAppIdentifier: String)", - parameters: (dAppIdentifier), - escapingParameters: (dAppIdentifier), + return cuckoo_manager.call("submit(pin: String)", + parameters: (pin), + escapingParameters: (pin), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.removeFromFavorites(dAppIdentifier: dAppIdentifier)) + defaultCall: __defaultImplStub!.submit(pin: pin)) } - struct __StubbingProxy_DAppListInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_PinSetupPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -17888,29 +16935,29 @@ import SubstrateSdk } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func start() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupPresenterProtocol.self, method: "start()", parameterMatchers: matchers)) } - func refresh() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func cancel() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorInputProtocol.self, method: "refresh()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupPresenterProtocol.self, method: "cancel()", parameterMatchers: matchers)) } - func addToFavorites(dApp: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DApp)> where M1.MatchedType == DApp { - let matchers: [Cuckoo.ParameterMatcher<(DApp)>] = [wrap(matchable: dApp) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorInputProtocol.self, method: "addToFavorites(dApp: DApp)", parameterMatchers: matchers)) + func activateBiometricAuth() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupPresenterProtocol.self, method: "activateBiometricAuth()", parameterMatchers: matchers)) } - func removeFromFavorites(dAppIdentifier: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: dAppIdentifier) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorInputProtocol.self, method: "removeFromFavorites(dAppIdentifier: String)", parameterMatchers: matchers)) + func submit(pin: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: pin) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupPresenterProtocol.self, method: "submit(pin: String)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppListInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_PinSetupPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -17925,33 +16972,33 @@ import SubstrateSdk @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { + func start() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("start()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func refresh() -> Cuckoo.__DoNotUse<(), Void> { + func cancel() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("refresh()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("cancel()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func addToFavorites(dApp: M1) -> Cuckoo.__DoNotUse<(DApp), Void> where M1.MatchedType == DApp { - let matchers: [Cuckoo.ParameterMatcher<(DApp)>] = [wrap(matchable: dApp) { $0 }] - return cuckoo_manager.verify("addToFavorites(dApp: DApp)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func activateBiometricAuth() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("activateBiometricAuth()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func removeFromFavorites(dAppIdentifier: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: dAppIdentifier) { $0 }] - return cuckoo_manager.verify("removeFromFavorites(dAppIdentifier: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func submit(pin: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: pin) { $0 }] + return cuckoo_manager.verify("submit(pin: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppListInteractorInputProtocolStub: DAppListInteractorInputProtocol { + class PinSetupPresenterProtocolStub: PinSetupPresenterProtocol { @@ -17959,25 +17006,25 @@ import SubstrateSdk - func setup() { + func start() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func refresh() { + func cancel() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func addToFavorites(dApp: DApp) { + func activateBiometricAuth() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func removeFromFavorites(dAppIdentifier: String) { + func submit(pin: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -17985,19 +17032,19 @@ import SubstrateSdk - class MockDAppListInteractorOutputProtocol: DAppListInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockPinSetupInteractorInputProtocol: PinSetupInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppListInteractorOutputProtocol + typealias MocksType = PinSetupInteractorInputProtocol - typealias Stubbing = __StubbingProxy_DAppListInteractorOutputProtocol - typealias Verification = __VerificationProxy_DAppListInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_PinSetupInteractorInputProtocol + typealias Verification = __VerificationProxy_PinSetupInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppListInteractorOutputProtocol? + private var __defaultImplStub: PinSetupInteractorInputProtocol? - func enableDefaultImplementation(_ stub: DAppListInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: PinSetupInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -18010,51 +17057,21 @@ import SubstrateSdk - func didReceive(walletResult: Result) { - - return cuckoo_manager.call("didReceive(walletResult: Result)", - parameters: (walletResult), - escapingParameters: (walletResult), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(walletResult: walletResult)) - - } - - - - func didReceive(dAppsResult: Result?) { - - return cuckoo_manager.call("didReceive(dAppsResult: Result?)", - parameters: (dAppsResult), - escapingParameters: (dAppsResult), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(dAppsResult: dAppsResult)) - - } - - - - func didReceiveFavoriteDapp(changes: [DataProviderChange]) { + func process(pin: String) { - return cuckoo_manager.call("didReceiveFavoriteDapp(changes: [DataProviderChange])", - parameters: (changes), - escapingParameters: (changes), + return cuckoo_manager.call("process(pin: String)", + parameters: (pin), + escapingParameters: (pin), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFavoriteDapp(changes: changes)) + defaultCall: __defaultImplStub!.process(pin: pin)) } - struct __StubbingProxy_DAppListInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_PinSetupInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -18062,24 +17079,14 @@ import SubstrateSdk } - func didReceive(walletResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: walletResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorOutputProtocol.self, method: "didReceive(walletResult: Result)", parameterMatchers: matchers)) - } - - func didReceive(dAppsResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result?)> where M1.OptionalMatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result?)>] = [wrap(matchable: dAppsResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorOutputProtocol.self, method: "didReceive(dAppsResult: Result?)", parameterMatchers: matchers)) - } - - func didReceiveFavoriteDapp(changes: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([DataProviderChange])> where M1.MatchedType == [DataProviderChange] { - let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListInteractorOutputProtocol.self, method: "didReceiveFavoriteDapp(changes: [DataProviderChange])", parameterMatchers: matchers)) + func process(pin: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: pin) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupInteractorInputProtocol.self, method: "process(pin: String)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppListInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_PinSetupInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -18094,27 +17101,15 @@ import SubstrateSdk @discardableResult - func didReceive(walletResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: walletResult) { $0 }] - return cuckoo_manager.verify("didReceive(walletResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(dAppsResult: M1) -> Cuckoo.__DoNotUse<(Result?), Void> where M1.OptionalMatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result?)>] = [wrap(matchable: dAppsResult) { $0 }] - return cuckoo_manager.verify("didReceive(dAppsResult: Result?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFavoriteDapp(changes: M1) -> Cuckoo.__DoNotUse<([DataProviderChange]), Void> where M1.MatchedType == [DataProviderChange] { - let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] - return cuckoo_manager.verify("didReceiveFavoriteDapp(changes: [DataProviderChange])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func process(pin: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: pin) { $0 }] + return cuckoo_manager.verify("process(pin: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppListInteractorOutputProtocolStub: DAppListInteractorOutputProtocol { + class PinSetupInteractorInputProtocolStub: PinSetupInteractorInputProtocol { @@ -18122,19 +17117,7 @@ import SubstrateSdk - func didReceive(walletResult: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(dAppsResult: Result?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFavoriteDapp(changes: [DataProviderChange]) { + func process(pin: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -18142,19 +17125,19 @@ import SubstrateSdk - class MockDAppListWireframeProtocol: DAppListWireframeProtocol, Cuckoo.ProtocolMock { + class MockPinSetupInteractorOutputProtocol: PinSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppListWireframeProtocol + typealias MocksType = PinSetupInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_DAppListWireframeProtocol - typealias Verification = __VerificationProxy_DAppListWireframeProtocol + typealias Stubbing = __StubbingProxy_PinSetupInteractorOutputProtocol + typealias Verification = __VerificationProxy_PinSetupInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppListWireframeProtocol? + private var __defaultImplStub: PinSetupInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: DAppListWireframeProtocol) { + func enableDefaultImplementation(_ stub: PinSetupInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -18167,66 +17150,51 @@ import SubstrateSdk - func showSearch(from view: DAppListViewProtocol?, delegate: DAppSearchDelegate) { - - return cuckoo_manager.call("showSearch(from: DAppListViewProtocol?, delegate: DAppSearchDelegate)", - parameters: (view, delegate), - escapingParameters: (view, delegate), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showSearch(from: view, delegate: delegate)) - - } - - - - func showBrowser(from view: DAppListViewProtocol?, for result: DAppSearchResult) { + func didSavePin() { - return cuckoo_manager.call("showBrowser(from: DAppListViewProtocol?, for: DAppSearchResult)", - parameters: (view, result), - escapingParameters: (view, result), + return cuckoo_manager.call("didSavePin()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showBrowser(from: view, for: result)) + defaultCall: __defaultImplStub!.didSavePin()) } - func showSetting(from view: DAppListViewProtocol?) { + func didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void) { - return cuckoo_manager.call("showSetting(from: DAppListViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", + parameters: (type, completionBlock), + escapingParameters: (type, completionBlock), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showSetting(from: view)) + defaultCall: __defaultImplStub!.didStartWaitingBiometryDecision(type: type, completionBlock: completionBlock)) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func didChangeState(from: PinSetupInteractor.PinSetupState) { - return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", - parameters: (url, view, style), - escapingParameters: (url, view, style), + return cuckoo_manager.call("didChangeState(from: PinSetupInteractor.PinSetupState)", + parameters: (from), + escapingParameters: (from), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) + defaultCall: __defaultImplStub!.didChangeState(from: from)) } - struct __StubbingProxy_DAppListWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_PinSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -18234,29 +17202,24 @@ import SubstrateSdk } - func showSearch(from view: M1, delegate: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppListViewProtocol?, DAppSearchDelegate)> where M1.OptionalMatchedType == DAppListViewProtocol, M2.MatchedType == DAppSearchDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?, DAppSearchDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListWireframeProtocol.self, method: "showSearch(from: DAppListViewProtocol?, delegate: DAppSearchDelegate)", parameterMatchers: matchers)) - } - - func showBrowser(from view: M1, for result: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppListViewProtocol?, DAppSearchResult)> where M1.OptionalMatchedType == DAppListViewProtocol, M2.MatchedType == DAppSearchResult { - let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?, DAppSearchResult)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: result) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListWireframeProtocol.self, method: "showBrowser(from: DAppListViewProtocol?, for: DAppSearchResult)", parameterMatchers: matchers)) + func didSavePin() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupInteractorOutputProtocol.self, method: "didSavePin()", parameterMatchers: matchers)) } - func showSetting(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppListViewProtocol?)> where M1.OptionalMatchedType == DAppListViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListWireframeProtocol.self, method: "showSetting(from: DAppListViewProtocol?)", parameterMatchers: matchers)) + func didStartWaitingBiometryDecision(type: M1, completionBlock: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(AvailableBiometryType, (Bool) -> Void)> where M1.MatchedType == AvailableBiometryType, M2.MatchedType == (Bool) -> Void { + let matchers: [Cuckoo.ParameterMatcher<(AvailableBiometryType, (Bool) -> Void)>] = [wrap(matchable: type) { $0.0 }, wrap(matchable: completionBlock) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupInteractorOutputProtocol.self, method: "didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", parameterMatchers: matchers)) } - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppListWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) + func didChangeState(from: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PinSetupInteractor.PinSetupState)> where M1.MatchedType == PinSetupInteractor.PinSetupState { + let matchers: [Cuckoo.ParameterMatcher<(PinSetupInteractor.PinSetupState)>] = [wrap(matchable: from) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupInteractorOutputProtocol.self, method: "didChangeState(from: PinSetupInteractor.PinSetupState)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppListWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_PinSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -18271,33 +17234,27 @@ import SubstrateSdk @discardableResult - func showSearch(from view: M1, delegate: M2) -> Cuckoo.__DoNotUse<(DAppListViewProtocol?, DAppSearchDelegate), Void> where M1.OptionalMatchedType == DAppListViewProtocol, M2.MatchedType == DAppSearchDelegate { - let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?, DAppSearchDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }] - return cuckoo_manager.verify("showSearch(from: DAppListViewProtocol?, delegate: DAppSearchDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showBrowser(from view: M1, for result: M2) -> Cuckoo.__DoNotUse<(DAppListViewProtocol?, DAppSearchResult), Void> where M1.OptionalMatchedType == DAppListViewProtocol, M2.MatchedType == DAppSearchResult { - let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?, DAppSearchResult)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: result) { $0.1 }] - return cuckoo_manager.verify("showBrowser(from: DAppListViewProtocol?, for: DAppSearchResult)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didSavePin() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didSavePin()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showSetting(from view: M1) -> Cuckoo.__DoNotUse<(DAppListViewProtocol?), Void> where M1.OptionalMatchedType == DAppListViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppListViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showSetting(from: DAppListViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStartWaitingBiometryDecision(type: M1, completionBlock: M2) -> Cuckoo.__DoNotUse<(AvailableBiometryType, (Bool) -> Void), Void> where M1.MatchedType == AvailableBiometryType, M2.MatchedType == (Bool) -> Void { + let matchers: [Cuckoo.ParameterMatcher<(AvailableBiometryType, (Bool) -> Void)>] = [wrap(matchable: type) { $0.0 }, wrap(matchable: completionBlock) { $0.1 }] + return cuckoo_manager.verify("didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didChangeState(from: M1) -> Cuckoo.__DoNotUse<(PinSetupInteractor.PinSetupState), Void> where M1.MatchedType == PinSetupInteractor.PinSetupState { + let matchers: [Cuckoo.ParameterMatcher<(PinSetupInteractor.PinSetupState)>] = [wrap(matchable: from) { $0 }] + return cuckoo_manager.verify("didChangeState(from: PinSetupInteractor.PinSetupState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppListWireframeProtocolStub: DAppListWireframeProtocol { + class PinSetupInteractorOutputProtocolStub: PinSetupInteractorOutputProtocol { @@ -18305,120 +17262,81 @@ import SubstrateSdk - func showSearch(from view: DAppListViewProtocol?, delegate: DAppSearchDelegate) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showBrowser(from view: DAppListViewProtocol?, for result: DAppSearchResult) { + func didSavePin() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showSetting(from view: DAppListViewProtocol?) { + func didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func didChangeState(from: PinSetupInteractor.PinSetupState) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import SubstrateSdk - - class MockDAppOperationConfirmViewProtocol: DAppOperationConfirmViewProtocol, Cuckoo.ProtocolMock { + class MockPinSetupWireframeProtocol: PinSetupWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppOperationConfirmViewProtocol + typealias MocksType = PinSetupWireframeProtocol - typealias Stubbing = __StubbingProxy_DAppOperationConfirmViewProtocol - typealias Verification = __VerificationProxy_DAppOperationConfirmViewProtocol + typealias Stubbing = __StubbingProxy_PinSetupWireframeProtocol + typealias Verification = __VerificationProxy_PinSetupWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppOperationConfirmViewProtocol? + private var __defaultImplStub: PinSetupWireframeProtocol? - func enableDefaultImplementation(_ stub: DAppOperationConfirmViewProtocol) { + func enableDefaultImplementation(_ stub: PinSetupWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - func didReceive(confimationViewModel: DAppOperationConfirmViewModel) { + func showMain(from view: PinSetupViewProtocol?) { - return cuckoo_manager.call("didReceive(confimationViewModel: DAppOperationConfirmViewModel)", - parameters: (confimationViewModel), - escapingParameters: (confimationViewModel), + return cuckoo_manager.call("showMain(from: PinSetupViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(confimationViewModel: confimationViewModel)) + defaultCall: __defaultImplStub!.showMain(from: view)) } - func didReceive(feeViewModel: DAppOperationFeeViewModel) { + func showSignup(from view: PinSetupViewProtocol?) { - return cuckoo_manager.call("didReceive(feeViewModel: DAppOperationFeeViewModel)", - parameters: (feeViewModel), - escapingParameters: (feeViewModel), + return cuckoo_manager.call("showSignup(from: PinSetupViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(feeViewModel: feeViewModel)) + defaultCall: __defaultImplStub!.showSignup(from: view)) } - struct __StubbingProxy_DAppOperationConfirmViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_PinSetupWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -18426,29 +17344,19 @@ import SubstrateSdk } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - func didReceive(confimationViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationConfirmViewModel)> where M1.MatchedType == DAppOperationConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewModel)>] = [wrap(matchable: confimationViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmViewProtocol.self, method: "didReceive(confimationViewModel: DAppOperationConfirmViewModel)", parameterMatchers: matchers)) + func showMain(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PinSetupViewProtocol?)> where M1.OptionalMatchedType == PinSetupViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(PinSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupWireframeProtocol.self, method: "showMain(from: PinSetupViewProtocol?)", parameterMatchers: matchers)) } - func didReceive(feeViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationFeeViewModel)> where M1.MatchedType == DAppOperationFeeViewModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationFeeViewModel)>] = [wrap(matchable: feeViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmViewProtocol.self, method: "didReceive(feeViewModel: DAppOperationFeeViewModel)", parameterMatchers: matchers)) + func showSignup(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PinSetupViewProtocol?)> where M1.OptionalMatchedType == PinSetupViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(PinSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockPinSetupWireframeProtocol.self, method: "showSignup(from: PinSetupViewProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppOperationConfirmViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_PinSetupWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -18460,66 +17368,136 @@ import SubstrateSdk } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceive(confimationViewModel: M1) -> Cuckoo.__DoNotUse<(DAppOperationConfirmViewModel), Void> where M1.MatchedType == DAppOperationConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewModel)>] = [wrap(matchable: confimationViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(confimationViewModel: DAppOperationConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showMain(from view: M1) -> Cuckoo.__DoNotUse<(PinSetupViewProtocol?), Void> where M1.OptionalMatchedType == PinSetupViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(PinSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showMain(from: PinSetupViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(feeViewModel: M1) -> Cuckoo.__DoNotUse<(DAppOperationFeeViewModel), Void> where M1.MatchedType == DAppOperationFeeViewModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationFeeViewModel)>] = [wrap(matchable: feeViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(feeViewModel: DAppOperationFeeViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showSignup(from view: M1) -> Cuckoo.__DoNotUse<(PinSetupViewProtocol?), Void> where M1.OptionalMatchedType == PinSetupViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(PinSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showSignup(from: PinSetupViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppOperationConfirmViewProtocolStub: DAppOperationConfirmViewProtocol { - + class PinSetupWireframeProtocolStub: PinSetupWireframeProtocol { + + + - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + + func showMain(from view: PinSetupViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - + + func showSignup(from view: PinSetupViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + +import Cuckoo +@testable import novawallet + +import UIKit + + + class MockRootPresenterProtocol: RootPresenterProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = RootPresenterProtocol + + typealias Stubbing = __StubbingProxy_RootPresenterProtocol + typealias Verification = __VerificationProxy_RootPresenterProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: RootPresenterProtocol? + func enableDefaultImplementation(_ stub: RootPresenterProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + - func didReceive(confimationViewModel: DAppOperationConfirmViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + + + func loadOnLaunch() { + + return cuckoo_manager.call("loadOnLaunch()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadOnLaunch()) + } + + struct __StubbingProxy_RootPresenterProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func loadOnLaunch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockRootPresenterProtocol.self, method: "loadOnLaunch()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_RootPresenterProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func loadOnLaunch() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("loadOnLaunch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class RootPresenterProtocolStub: RootPresenterProtocol { + + + + - func didReceive(feeViewModel: DAppOperationFeeViewModel) { + + func loadOnLaunch() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -18527,19 +17505,19 @@ import SubstrateSdk - class MockDAppOperationConfirmPresenterProtocol: DAppOperationConfirmPresenterProtocol, Cuckoo.ProtocolMock { + class MockRootWireframeProtocol: RootWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppOperationConfirmPresenterProtocol + typealias MocksType = RootWireframeProtocol - typealias Stubbing = __StubbingProxy_DAppOperationConfirmPresenterProtocol - typealias Verification = __VerificationProxy_DAppOperationConfirmPresenterProtocol + typealias Stubbing = __StubbingProxy_RootWireframeProtocol + typealias Verification = __VerificationProxy_RootWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppOperationConfirmPresenterProtocol? + private var __defaultImplStub: RootWireframeProtocol? - func enableDefaultImplementation(_ stub: DAppOperationConfirmPresenterProtocol) { + func enableDefaultImplementation(_ stub: RootWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -18552,66 +17530,66 @@ import SubstrateSdk - func setup() { + func showLocalAuthentication(on view: UIWindow) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("showLocalAuthentication(on: UIWindow)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.showLocalAuthentication(on: view)) } - func confirm() { + func showOnboarding(on view: UIWindow) { - return cuckoo_manager.call("confirm()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("showOnboarding(on: UIWindow)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.confirm()) + defaultCall: __defaultImplStub!.showOnboarding(on: view)) } - func reject() { + func showPincodeSetup(on view: UIWindow) { - return cuckoo_manager.call("reject()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("showPincodeSetup(on: UIWindow)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reject()) + defaultCall: __defaultImplStub!.showPincodeSetup(on: view)) } - func activateTxDetails() { + func showBroken(on view: UIWindow) { - return cuckoo_manager.call("activateTxDetails()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("showBroken(on: UIWindow)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activateTxDetails()) + defaultCall: __defaultImplStub!.showBroken(on: view)) } - struct __StubbingProxy_DAppOperationConfirmPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_RootWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -18619,29 +17597,29 @@ import SubstrateSdk } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + func showLocalAuthentication(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(UIWindow)> where M1.MatchedType == UIWindow { + let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockRootWireframeProtocol.self, method: "showLocalAuthentication(on: UIWindow)", parameterMatchers: matchers)) } - func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + func showOnboarding(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(UIWindow)> where M1.MatchedType == UIWindow { + let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockRootWireframeProtocol.self, method: "showOnboarding(on: UIWindow)", parameterMatchers: matchers)) } - func reject() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmPresenterProtocol.self, method: "reject()", parameterMatchers: matchers)) + func showPincodeSetup(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(UIWindow)> where M1.MatchedType == UIWindow { + let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockRootWireframeProtocol.self, method: "showPincodeSetup(on: UIWindow)", parameterMatchers: matchers)) } - func activateTxDetails() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmPresenterProtocol.self, method: "activateTxDetails()", parameterMatchers: matchers)) + func showBroken(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(UIWindow)> where M1.MatchedType == UIWindow { + let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockRootWireframeProtocol.self, method: "showBroken(on: UIWindow)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppOperationConfirmPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_RootWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -18656,33 +17634,33 @@ import SubstrateSdk @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showLocalAuthentication(on view: M1) -> Cuckoo.__DoNotUse<(UIWindow), Void> where M1.MatchedType == UIWindow { + let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showLocalAuthentication(on: UIWindow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func confirm() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showOnboarding(on view: M1) -> Cuckoo.__DoNotUse<(UIWindow), Void> where M1.MatchedType == UIWindow { + let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showOnboarding(on: UIWindow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func reject() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("reject()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showPincodeSetup(on view: M1) -> Cuckoo.__DoNotUse<(UIWindow), Void> where M1.MatchedType == UIWindow { + let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showPincodeSetup(on: UIWindow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func activateTxDetails() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateTxDetails()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showBroken(on view: M1) -> Cuckoo.__DoNotUse<(UIWindow), Void> where M1.MatchedType == UIWindow { + let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showBroken(on: UIWindow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppOperationConfirmPresenterProtocolStub: DAppOperationConfirmPresenterProtocol { + class RootWireframeProtocolStub: RootWireframeProtocol { @@ -18690,25 +17668,25 @@ import SubstrateSdk - func setup() { + func showLocalAuthentication(on view: UIWindow) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func confirm() { + func showOnboarding(on view: UIWindow) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func reject() { + func showPincodeSetup(on view: UIWindow) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func activateTxDetails() { + func showBroken(on view: UIWindow) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -18716,19 +17694,19 @@ import SubstrateSdk - class MockDAppOperationConfirmInteractorInputProtocol: DAppOperationConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockRootInteractorInputProtocol: RootInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppOperationConfirmInteractorInputProtocol + typealias MocksType = RootInteractorInputProtocol - typealias Stubbing = __StubbingProxy_DAppOperationConfirmInteractorInputProtocol - typealias Verification = __VerificationProxy_DAppOperationConfirmInteractorInputProtocol + typealias Stubbing = __StubbingProxy_RootInteractorInputProtocol + typealias Verification = __VerificationProxy_RootInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppOperationConfirmInteractorInputProtocol? + private var __defaultImplStub: RootInteractorInputProtocol? - func enableDefaultImplementation(_ stub: DAppOperationConfirmInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: RootInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -18756,66 +17734,21 @@ import SubstrateSdk - func estimateFee() { - - return cuckoo_manager.call("estimateFee()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.estimateFee()) - - } - - - - func confirm() { - - return cuckoo_manager.call("confirm()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.confirm()) - - } - - - - func reject() { - - return cuckoo_manager.call("reject()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.reject()) - - } - - - - func prepareTxDetails() { + func decideModuleSynchroniously() { - return cuckoo_manager.call("prepareTxDetails()", + return cuckoo_manager.call("decideModuleSynchroniously()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.prepareTxDetails()) + defaultCall: __defaultImplStub!.decideModuleSynchroniously()) } - struct __StubbingProxy_DAppOperationConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_RootInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -18825,32 +17758,17 @@ import SubstrateSdk func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) - } - - func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "confirm()", parameterMatchers: matchers)) - } - - func reject() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "reject()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func prepareTxDetails() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func decideModuleSynchroniously() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorInputProtocol.self, method: "prepareTxDetails()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorInputProtocol.self, method: "decideModuleSynchroniously()", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppOperationConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_RootInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -18871,33 +17789,15 @@ import SubstrateSdk } @discardableResult - func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func confirm() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func reject() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("reject()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func prepareTxDetails() -> Cuckoo.__DoNotUse<(), Void> { + func decideModuleSynchroniously() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("prepareTxDetails()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("decideModuleSynchroniously()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppOperationConfirmInteractorInputProtocolStub: DAppOperationConfirmInteractorInputProtocol { + class RootInteractorInputProtocolStub: RootInteractorInputProtocol { @@ -18911,25 +17811,7 @@ import SubstrateSdk - func estimateFee() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func confirm() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func reject() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func prepareTxDetails() { + func decideModuleSynchroniously() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -18937,19 +17819,19 @@ import SubstrateSdk - class MockDAppOperationConfirmInteractorOutputProtocol: DAppOperationConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockRootInteractorOutputProtocol: RootInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppOperationConfirmInteractorOutputProtocol + typealias MocksType = RootInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_DAppOperationConfirmInteractorOutputProtocol - typealias Verification = __VerificationProxy_DAppOperationConfirmInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_RootInteractorOutputProtocol + typealias Verification = __VerificationProxy_RootInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppOperationConfirmInteractorOutputProtocol? + private var __defaultImplStub: RootInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: DAppOperationConfirmInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: RootInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -18962,81 +17844,66 @@ import SubstrateSdk - func didReceive(modelResult: Result) { + func didDecideOnboarding() { - return cuckoo_manager.call("didReceive(modelResult: Result)", - parameters: (modelResult), - escapingParameters: (modelResult), + return cuckoo_manager.call("didDecideOnboarding()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(modelResult: modelResult)) + defaultCall: __defaultImplStub!.didDecideOnboarding()) } - func didReceive(feeResult: Result) { + func didDecideLocalAuthentication() { - return cuckoo_manager.call("didReceive(feeResult: Result)", - parameters: (feeResult), - escapingParameters: (feeResult), + return cuckoo_manager.call("didDecideLocalAuthentication()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(feeResult: feeResult)) + defaultCall: __defaultImplStub!.didDecideLocalAuthentication()) } - func didReceive(priceResult: Result) { + func didDecidePincodeSetup() { - return cuckoo_manager.call("didReceive(priceResult: Result)", - parameters: (priceResult), - escapingParameters: (priceResult), + return cuckoo_manager.call("didDecidePincodeSetup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(priceResult: priceResult)) + defaultCall: __defaultImplStub!.didDecidePincodeSetup()) } - func didReceive(responseResult: Result, for request: DAppOperationRequest) { + func didDecideBroken() { - return cuckoo_manager.call("didReceive(responseResult: Result, for: DAppOperationRequest)", - parameters: (responseResult, request), - escapingParameters: (responseResult, request), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(responseResult: responseResult, for: request)) - - } - - - - func didReceive(txDetailsResult: Result) { - - return cuckoo_manager.call("didReceive(txDetailsResult: Result)", - parameters: (txDetailsResult), - escapingParameters: (txDetailsResult), + return cuckoo_manager.call("didDecideBroken()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(txDetailsResult: txDetailsResult)) + defaultCall: __defaultImplStub!.didDecideBroken()) } - struct __StubbingProxy_DAppOperationConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_RootInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -19044,34 +17911,29 @@ import SubstrateSdk } - func didReceive(modelResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: modelResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(modelResult: Result)", parameterMatchers: matchers)) - } - - func didReceive(feeResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: feeResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(feeResult: Result)", parameterMatchers: matchers)) + func didDecideOnboarding() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, method: "didDecideOnboarding()", parameterMatchers: matchers)) } - func didReceive(priceResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(priceResult: Result)", parameterMatchers: matchers)) + func didDecideLocalAuthentication() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, method: "didDecideLocalAuthentication()", parameterMatchers: matchers)) } - func didReceive(responseResult: M1, for request: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Result, DAppOperationRequest)> where M1.MatchedType == Result, M2.MatchedType == DAppOperationRequest { - let matchers: [Cuckoo.ParameterMatcher<(Result, DAppOperationRequest)>] = [wrap(matchable: responseResult) { $0.0 }, wrap(matchable: request) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(responseResult: Result, for: DAppOperationRequest)", parameterMatchers: matchers)) + func didDecidePincodeSetup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, method: "didDecidePincodeSetup()", parameterMatchers: matchers)) } - func didReceive(txDetailsResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: txDetailsResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmInteractorOutputProtocol.self, method: "didReceive(txDetailsResult: Result)", parameterMatchers: matchers)) + func didDecideBroken() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, method: "didDecideBroken()", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppOperationConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_RootInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -19086,39 +17948,33 @@ import SubstrateSdk @discardableResult - func didReceive(modelResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: modelResult) { $0 }] - return cuckoo_manager.verify("didReceive(modelResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(feeResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: feeResult) { $0 }] - return cuckoo_manager.verify("didReceive(feeResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didDecideOnboarding() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didDecideOnboarding()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(priceResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] - return cuckoo_manager.verify("didReceive(priceResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didDecideLocalAuthentication() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didDecideLocalAuthentication()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(responseResult: M1, for request: M2) -> Cuckoo.__DoNotUse<(Result, DAppOperationRequest), Void> where M1.MatchedType == Result, M2.MatchedType == DAppOperationRequest { - let matchers: [Cuckoo.ParameterMatcher<(Result, DAppOperationRequest)>] = [wrap(matchable: responseResult) { $0.0 }, wrap(matchable: request) { $0.1 }] - return cuckoo_manager.verify("didReceive(responseResult: Result, for: DAppOperationRequest)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didDecidePincodeSetup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didDecidePincodeSetup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(txDetailsResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: txDetailsResult) { $0 }] - return cuckoo_manager.verify("didReceive(txDetailsResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didDecideBroken() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didDecideBroken()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppOperationConfirmInteractorOutputProtocolStub: DAppOperationConfirmInteractorOutputProtocol { + class RootInteractorOutputProtocolStub: RootInteractorOutputProtocol { @@ -19126,123 +17982,121 @@ import SubstrateSdk - func didReceive(modelResult: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(feeResult: Result) { + func didDecideOnboarding() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(priceResult: Result) { + func didDecideLocalAuthentication() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(responseResult: Result, for request: DAppOperationRequest) { + func didDecidePincodeSetup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(txDetailsResult: Result) { + func didDecideBroken() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet - class MockDAppOperationConfirmWireframeProtocol: DAppOperationConfirmWireframeProtocol, Cuckoo.ProtocolMock { +import Foundation +import UIKit.UIImage + + + class MockSettingsViewProtocol: SettingsViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppOperationConfirmWireframeProtocol + typealias MocksType = SettingsViewProtocol - typealias Stubbing = __StubbingProxy_DAppOperationConfirmWireframeProtocol - typealias Verification = __VerificationProxy_DAppOperationConfirmWireframeProtocol + typealias Stubbing = __StubbingProxy_SettingsViewProtocol + typealias Verification = __VerificationProxy_SettingsViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppOperationConfirmWireframeProtocol? + private var __defaultImplStub: SettingsViewProtocol? - func enableDefaultImplementation(_ stub: DAppOperationConfirmWireframeProtocol) { + func enableDefaultImplementation(_ stub: SettingsViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - - - func close(view: DAppOperationConfirmViewProtocol?) { - - return cuckoo_manager.call("close(view: DAppOperationConfirmViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.close(view: view)) + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } } - func showTxDetails(from view: DAppOperationConfirmViewProtocol?, json: JSON) { - - return cuckoo_manager.call("showTxDetails(from: DAppOperationConfirmViewProtocol?, json: JSON)", - parameters: (view, json), - escapingParameters: (view, json), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showTxDetails(from: view, json: json)) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } + + + - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + + func reload(sections: [(SettingsSection, [SettingsCellViewModel])]) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("reload(sections: [(SettingsSection, [SettingsCellViewModel])])", + parameters: (sections), + escapingParameters: (sections), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.reload(sections: sections)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didLoad(userViewModel: SettingsAccountViewModel) { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("didLoad(userViewModel: SettingsAccountViewModel)", + parameters: (userViewModel), + escapingParameters: (userViewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.didLoad(userViewModel: userViewModel)) } - struct __StubbingProxy_DAppOperationConfirmWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SettingsViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -19250,29 +18104,29 @@ import SubstrateSdk } - func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationConfirmViewProtocol?)> where M1.OptionalMatchedType == DAppOperationConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmWireframeProtocol.self, method: "close(view: DAppOperationConfirmViewProtocol?)", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func showTxDetails(from view: M1, json: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationConfirmViewProtocol?, JSON)> where M1.OptionalMatchedType == DAppOperationConfirmViewProtocol, M2.MatchedType == JSON { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewProtocol?, JSON)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: json) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmWireframeProtocol.self, method: "showTxDetails(from: DAppOperationConfirmViewProtocol?, json: JSON)", parameterMatchers: matchers)) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + + func reload(sections: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([(SettingsSection, [SettingsCellViewModel])])> where M1.MatchedType == [(SettingsSection, [SettingsCellViewModel])] { + let matchers: [Cuckoo.ParameterMatcher<([(SettingsSection, [SettingsCellViewModel])])>] = [wrap(matchable: sections) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsViewProtocol.self, method: "reload(sections: [(SettingsSection, [SettingsCellViewModel])])", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didLoad(userViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SettingsAccountViewModel)> where M1.MatchedType == SettingsAccountViewModel { + let matchers: [Cuckoo.ParameterMatcher<(SettingsAccountViewModel)>] = [wrap(matchable: userViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsViewProtocol.self, method: "didLoad(userViewModel: SettingsAccountViewModel)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppOperationConfirmWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SettingsViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -19284,62 +18138,66 @@ import SubstrateSdk } - - @discardableResult - func close(view: M1) -> Cuckoo.__DoNotUse<(DAppOperationConfirmViewProtocol?), Void> where M1.OptionalMatchedType == DAppOperationConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(view: DAppOperationConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func showTxDetails(from view: M1, json: M2) -> Cuckoo.__DoNotUse<(DAppOperationConfirmViewProtocol?, JSON), Void> where M1.OptionalMatchedType == DAppOperationConfirmViewProtocol, M2.MatchedType == JSON { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationConfirmViewProtocol?, JSON)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: json) { $0.1 }] - return cuckoo_manager.verify("showTxDetails(from: DAppOperationConfirmViewProtocol?, json: JSON)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload(sections: M1) -> Cuckoo.__DoNotUse<([(SettingsSection, [SettingsCellViewModel])]), Void> where M1.MatchedType == [(SettingsSection, [SettingsCellViewModel])] { + let matchers: [Cuckoo.ParameterMatcher<([(SettingsSection, [SettingsCellViewModel])])>] = [wrap(matchable: sections) { $0 }] + return cuckoo_manager.verify("reload(sections: [(SettingsSection, [SettingsCellViewModel])])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didLoad(userViewModel: M1) -> Cuckoo.__DoNotUse<(SettingsAccountViewModel), Void> where M1.MatchedType == SettingsAccountViewModel { + let matchers: [Cuckoo.ParameterMatcher<(SettingsAccountViewModel)>] = [wrap(matchable: userViewModel) { $0 }] + return cuckoo_manager.verify("didLoad(userViewModel: SettingsAccountViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppOperationConfirmWireframeProtocolStub: DAppOperationConfirmWireframeProtocol { - - + class SettingsViewProtocolStub: SettingsViewProtocol { + - + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + - func close(view: DAppOperationConfirmViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + - - func showTxDetails(from view: DAppOperationConfirmViewProtocol?, json: JSON) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func reload(sections: [(SettingsSection, [SettingsCellViewModel])]) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didLoad(userViewModel: SettingsAccountViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -19347,46 +18205,105 @@ import SubstrateSdk - class MockDAppOperationConfirmDelegate: DAppOperationConfirmDelegate, Cuckoo.ProtocolMock { + class MockSettingsPresenterProtocol: SettingsPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppOperationConfirmDelegate + typealias MocksType = SettingsPresenterProtocol - typealias Stubbing = __StubbingProxy_DAppOperationConfirmDelegate - typealias Verification = __VerificationProxy_DAppOperationConfirmDelegate + typealias Stubbing = __StubbingProxy_SettingsPresenterProtocol + typealias Verification = __VerificationProxy_SettingsPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppOperationConfirmDelegate? + private var __defaultImplStub: SettingsPresenterProtocol? - func enableDefaultImplementation(_ stub: DAppOperationConfirmDelegate) { + func enableDefaultImplementation(_ stub: SettingsPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + + var appNameText: String { + get { + return cuckoo_manager.getter("appNameText", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.appNameText) + } + + } + - func didReceiveConfirmationResponse(_ response: DAppOperationResponse, for request: DAppOperationRequest) { + func setup() { - return cuckoo_manager.call("didReceiveConfirmationResponse(_: DAppOperationResponse, for: DAppOperationRequest)", - parameters: (response, request), - escapingParameters: (response, request), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveConfirmationResponse(response, for: request)) + defaultCall: __defaultImplStub!.setup()) + + } + + + + func actionRow(_ row: SettingsRow) { + + return cuckoo_manager.call("actionRow(_: SettingsRow)", + parameters: (row), + escapingParameters: (row), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.actionRow(row)) + + } + + + + func handleWalletAction() { + + return cuckoo_manager.call("handleWalletAction()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.handleWalletAction()) + + } + + + + func handleSwitchAction() { + + return cuckoo_manager.call("handleSwitchAction()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.handleSwitchAction()) } - struct __StubbingProxy_DAppOperationConfirmDelegate: Cuckoo.StubbingProxy { + struct __StubbingProxy_SettingsPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -19394,14 +18311,34 @@ import SubstrateSdk } - func didReceiveConfirmationResponse(_ response: M1, for request: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppOperationResponse, DAppOperationRequest)> where M1.MatchedType == DAppOperationResponse, M2.MatchedType == DAppOperationRequest { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationResponse, DAppOperationRequest)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: request) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppOperationConfirmDelegate.self, method: "didReceiveConfirmationResponse(_: DAppOperationResponse, for: DAppOperationRequest)", parameterMatchers: matchers)) + var appNameText: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "appNameText") + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func actionRow(_ row: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SettingsRow)> where M1.MatchedType == SettingsRow { + let matchers: [Cuckoo.ParameterMatcher<(SettingsRow)>] = [wrap(matchable: row) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsPresenterProtocol.self, method: "actionRow(_: SettingsRow)", parameterMatchers: matchers)) + } + + func handleWalletAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsPresenterProtocol.self, method: "handleWalletAction()", parameterMatchers: matchers)) + } + + func handleSwitchAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsPresenterProtocol.self, method: "handleSwitchAction()", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppOperationConfirmDelegate: Cuckoo.VerificationProxy { + struct __VerificationProxy_SettingsPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -19413,18 +18350,50 @@ import SubstrateSdk } + + var appNameText: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "appNameText", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func didReceiveConfirmationResponse(_ response: M1, for request: M2) -> Cuckoo.__DoNotUse<(DAppOperationResponse, DAppOperationRequest), Void> where M1.MatchedType == DAppOperationResponse, M2.MatchedType == DAppOperationRequest { - let matchers: [Cuckoo.ParameterMatcher<(DAppOperationResponse, DAppOperationRequest)>] = [wrap(matchable: response) { $0.0 }, wrap(matchable: request) { $0.1 }] - return cuckoo_manager.verify("didReceiveConfirmationResponse(_: DAppOperationResponse, for: DAppOperationRequest)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func actionRow(_ row: M1) -> Cuckoo.__DoNotUse<(SettingsRow), Void> where M1.MatchedType == SettingsRow { + let matchers: [Cuckoo.ParameterMatcher<(SettingsRow)>] = [wrap(matchable: row) { $0 }] + return cuckoo_manager.verify("actionRow(_: SettingsRow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func handleWalletAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("handleWalletAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func handleSwitchAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("handleSwitchAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppOperationConfirmDelegateStub: DAppOperationConfirmDelegate { + class SettingsPresenterProtocolStub: SettingsPresenterProtocol { + + + + var appNameText: String { + get { + return DefaultValueRegistry.defaultValue(for: (String).self) + } + + } @@ -19432,102 +18401,87 @@ import SubstrateSdk - func didReceiveConfirmationResponse(_ response: DAppOperationResponse, for request: DAppOperationRequest) { + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func actionRow(_ row: SettingsRow) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func handleWalletAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func handleSwitchAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import RobinHood - - class MockDAppSearchViewProtocol: DAppSearchViewProtocol, Cuckoo.ProtocolMock { + class MockSettingsViewModelFactoryProtocol: SettingsViewModelFactoryProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppSearchViewProtocol + typealias MocksType = SettingsViewModelFactoryProtocol - typealias Stubbing = __StubbingProxy_DAppSearchViewProtocol - typealias Verification = __VerificationProxy_DAppSearchViewProtocol + typealias Stubbing = __StubbingProxy_SettingsViewModelFactoryProtocol + typealias Verification = __VerificationProxy_SettingsViewModelFactoryProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppSearchViewProtocol? + private var __defaultImplStub: SettingsViewModelFactoryProtocol? - func enableDefaultImplementation(_ stub: DAppSearchViewProtocol) { + func enableDefaultImplementation(_ stub: SettingsViewModelFactoryProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - func didReceive(initialQuery: String) { + func createAccountViewModel(for wallet: MetaAccountModel) -> SettingsAccountViewModel { - return cuckoo_manager.call("didReceive(initialQuery: String)", - parameters: (initialQuery), - escapingParameters: (initialQuery), + return cuckoo_manager.call("createAccountViewModel(for: MetaAccountModel) -> SettingsAccountViewModel", + parameters: (wallet), + escapingParameters: (wallet), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(initialQuery: initialQuery)) + defaultCall: __defaultImplStub!.createAccountViewModel(for: wallet)) } - func didReceiveDApp(viewModels: [DAppViewModel]) { + func createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])] { - return cuckoo_manager.call("didReceiveDApp(viewModels: [DAppViewModel])", - parameters: (viewModels), - escapingParameters: (viewModels), + return cuckoo_manager.call("createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])]", + parameters: (language, currency, locale), + escapingParameters: (language, currency, locale), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveDApp(viewModels: viewModels)) + defaultCall: __defaultImplStub!.createSectionViewModels(language: language, currency: currency, locale: locale)) } - struct __StubbingProxy_DAppSearchViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SettingsViewModelFactoryProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -19535,29 +18489,19 @@ import RobinHood } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - func didReceive(initialQuery: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: initialQuery) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchViewProtocol.self, method: "didReceive(initialQuery: String)", parameterMatchers: matchers)) + func createAccountViewModel(for wallet: M1) -> Cuckoo.ProtocolStubFunction<(MetaAccountModel), SettingsAccountViewModel> where M1.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsViewModelFactoryProtocol.self, method: "createAccountViewModel(for: MetaAccountModel) -> SettingsAccountViewModel", parameterMatchers: matchers)) } - func didReceiveDApp(viewModels: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([DAppViewModel])> where M1.MatchedType == [DAppViewModel] { - let matchers: [Cuckoo.ParameterMatcher<([DAppViewModel])>] = [wrap(matchable: viewModels) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchViewProtocol.self, method: "didReceiveDApp(viewModels: [DAppViewModel])", parameterMatchers: matchers)) + func createSectionViewModels(language: M1, currency: M2, locale: M3) -> Cuckoo.ProtocolStubFunction<(Language?, String?, Locale), [(SettingsSection, [SettingsCellViewModel])]> where M1.OptionalMatchedType == Language, M2.OptionalMatchedType == String, M3.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<(Language?, String?, Locale)>] = [wrap(matchable: language) { $0.0 }, wrap(matchable: currency) { $0.1 }, wrap(matchable: locale) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsViewModelFactoryProtocol.self, method: "createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])]", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppSearchViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SettingsViewModelFactoryProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -19569,52 +18513,24 @@ import RobinHood } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceive(initialQuery: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: initialQuery) { $0 }] - return cuckoo_manager.verify("didReceive(initialQuery: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func createAccountViewModel(for wallet: M1) -> Cuckoo.__DoNotUse<(MetaAccountModel), SettingsAccountViewModel> where M1.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] + return cuckoo_manager.verify("createAccountViewModel(for: MetaAccountModel) -> SettingsAccountViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveDApp(viewModels: M1) -> Cuckoo.__DoNotUse<([DAppViewModel]), Void> where M1.MatchedType == [DAppViewModel] { - let matchers: [Cuckoo.ParameterMatcher<([DAppViewModel])>] = [wrap(matchable: viewModels) { $0 }] - return cuckoo_manager.verify("didReceiveDApp(viewModels: [DAppViewModel])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func createSectionViewModels(language: M1, currency: M2, locale: M3) -> Cuckoo.__DoNotUse<(Language?, String?, Locale), [(SettingsSection, [SettingsCellViewModel])]> where M1.OptionalMatchedType == Language, M2.OptionalMatchedType == String, M3.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<(Language?, String?, Locale)>] = [wrap(matchable: language) { $0.0 }, wrap(matchable: currency) { $0.1 }, wrap(matchable: locale) { $0.2 }] + return cuckoo_manager.verify("createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])]", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppSearchViewProtocolStub: DAppSearchViewProtocol { - - - - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - - - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } + class SettingsViewModelFactoryProtocolStub: SettingsViewModelFactoryProtocol { @@ -19622,33 +18538,33 @@ import RobinHood - func didReceive(initialQuery: String) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func createAccountViewModel(for wallet: MetaAccountModel) -> SettingsAccountViewModel { + return DefaultValueRegistry.defaultValue(for: (SettingsAccountViewModel).self) } - func didReceiveDApp(viewModels: [DAppViewModel]) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])] { + return DefaultValueRegistry.defaultValue(for: ([(SettingsSection, [SettingsCellViewModel])]).self) } } - class MockDAppSearchPresenterProtocol: DAppSearchPresenterProtocol, Cuckoo.ProtocolMock { + class MockSettingsInteractorInputProtocol: SettingsInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppSearchPresenterProtocol + typealias MocksType = SettingsInteractorInputProtocol - typealias Stubbing = __StubbingProxy_DAppSearchPresenterProtocol - typealias Verification = __VerificationProxy_DAppSearchPresenterProtocol + typealias Stubbing = __StubbingProxy_SettingsInteractorInputProtocol + typealias Verification = __VerificationProxy_SettingsInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppSearchPresenterProtocol? + private var __defaultImplStub: SettingsInteractorInputProtocol? - func enableDefaultImplementation(_ stub: DAppSearchPresenterProtocol) { + func enableDefaultImplementation(_ stub: SettingsInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -19674,68 +18590,8 @@ import RobinHood } - - - func updateSearch(query: String) { - - return cuckoo_manager.call("updateSearch(query: String)", - parameters: (query), - escapingParameters: (query), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.updateSearch(query: query)) - - } - - - - func selectDApp(viewModel: DAppViewModel) { - - return cuckoo_manager.call("selectDApp(viewModel: DAppViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.selectDApp(viewModel: viewModel)) - - } - - - - func selectSearchQuery() { - - return cuckoo_manager.call("selectSearchQuery()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.selectSearchQuery()) - - } - - - - func cancel() { - - return cuckoo_manager.call("cancel()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.cancel()) - - } - - struct __StubbingProxy_DAppSearchPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SettingsInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -19745,32 +18601,12 @@ import RobinHood func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func updateSearch(query: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: query) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "updateSearch(query: String)", parameterMatchers: matchers)) - } - - func selectDApp(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppViewModel)> where M1.MatchedType == DAppViewModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "selectDApp(viewModel: DAppViewModel)", parameterMatchers: matchers)) - } - - func selectSearchQuery() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "selectSearchQuery()", parameterMatchers: matchers)) - } - - func cancel() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchPresenterProtocol.self, method: "cancel()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockSettingsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppSearchPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SettingsInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -19790,34 +18626,10 @@ import RobinHood return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - @discardableResult - func updateSearch(query: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: query) { $0 }] - return cuckoo_manager.verify("updateSearch(query: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func selectDApp(viewModel: M1) -> Cuckoo.__DoNotUse<(DAppViewModel), Void> where M1.MatchedType == DAppViewModel { - let matchers: [Cuckoo.ParameterMatcher<(DAppViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("selectDApp(viewModel: DAppViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func selectSearchQuery() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectSearchQuery()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func cancel() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("cancel()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } - class DAppSearchPresenterProtocolStub: DAppSearchPresenterProtocol { + class SettingsInteractorInputProtocolStub: SettingsInteractorInputProtocol { @@ -19829,47 +18641,23 @@ import RobinHood return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - func updateSearch(query: String) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func selectDApp(viewModel: DAppViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func selectSearchQuery() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func cancel() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - } - class MockDAppSearchInteractorInputProtocol: DAppSearchInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockSettingsInteractorOutputProtocol: SettingsInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppSearchInteractorInputProtocol + typealias MocksType = SettingsInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_DAppSearchInteractorInputProtocol - typealias Verification = __VerificationProxy_DAppSearchInteractorInputProtocol + typealias Stubbing = __StubbingProxy_SettingsInteractorOutputProtocol + typealias Verification = __VerificationProxy_SettingsInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppSearchInteractorInputProtocol? + private var __defaultImplStub: SettingsInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: DAppSearchInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: SettingsInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -19882,129 +18670,51 @@ import RobinHood - func setup() { + func didReceive(wallet: MetaAccountModel) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(wallet: MetaAccountModel)", + parameters: (wallet), + escapingParameters: (wallet), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.didReceive(wallet: wallet)) } - - struct __StubbingProxy_DAppSearchInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_DAppSearchInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class DAppSearchInteractorInputProtocolStub: DAppSearchInteractorInputProtocol { - - - - - - - - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - - - class MockDAppSearchInteractorOutputProtocol: DAppSearchInteractorOutputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = DAppSearchInteractorOutputProtocol - - typealias Stubbing = __StubbingProxy_DAppSearchInteractorOutputProtocol - typealias Verification = __VerificationProxy_DAppSearchInteractorOutputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: DAppSearchInteractorOutputProtocol? - - func enableDefaultImplementation(_ stub: DAppSearchInteractorOutputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - - - func didReceive(dAppsResult: Result) { + func didReceiveUserDataProvider(error: Error) { - return cuckoo_manager.call("didReceive(dAppsResult: Result)", - parameters: (dAppsResult), - escapingParameters: (dAppsResult), + return cuckoo_manager.call("didReceiveUserDataProvider(error: Error)", + parameters: (error), + escapingParameters: (error), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(dAppsResult: dAppsResult)) + defaultCall: __defaultImplStub!.didReceiveUserDataProvider(error: error)) } - func didReceiveFavorite(changes: [DataProviderChange]) { + func didReceive(currencyCode: String) { - return cuckoo_manager.call("didReceiveFavorite(changes: [DataProviderChange])", - parameters: (changes), - escapingParameters: (changes), + return cuckoo_manager.call("didReceive(currencyCode: String)", + parameters: (currencyCode), + escapingParameters: (currencyCode), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFavorite(changes: changes)) + defaultCall: __defaultImplStub!.didReceive(currencyCode: currencyCode)) } - struct __StubbingProxy_DAppSearchInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SettingsInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -20012,19 +18722,24 @@ import RobinHood } - func didReceive(dAppsResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: dAppsResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchInteractorOutputProtocol.self, method: "didReceive(dAppsResult: Result)", parameterMatchers: matchers)) + func didReceive(wallet: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(MetaAccountModel)> where M1.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsInteractorOutputProtocol.self, method: "didReceive(wallet: MetaAccountModel)", parameterMatchers: matchers)) } - func didReceiveFavorite(changes: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([DataProviderChange])> where M1.MatchedType == [DataProviderChange] { - let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchInteractorOutputProtocol.self, method: "didReceiveFavorite(changes: [DataProviderChange])", parameterMatchers: matchers)) + func didReceiveUserDataProvider(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsInteractorOutputProtocol.self, method: "didReceiveUserDataProvider(error: Error)", parameterMatchers: matchers)) + } + + func didReceive(currencyCode: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: currencyCode) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsInteractorOutputProtocol.self, method: "didReceive(currencyCode: String)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppSearchInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SettingsInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -20039,21 +18754,27 @@ import RobinHood @discardableResult - func didReceive(dAppsResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: dAppsResult) { $0 }] - return cuckoo_manager.verify("didReceive(dAppsResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(wallet: M1) -> Cuckoo.__DoNotUse<(MetaAccountModel), Void> where M1.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] + return cuckoo_manager.verify("didReceive(wallet: MetaAccountModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveFavorite(changes: M1) -> Cuckoo.__DoNotUse<([DataProviderChange]), Void> where M1.MatchedType == [DataProviderChange] { - let matchers: [Cuckoo.ParameterMatcher<([DataProviderChange])>] = [wrap(matchable: changes) { $0 }] - return cuckoo_manager.verify("didReceiveFavorite(changes: [DataProviderChange])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveUserDataProvider(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return cuckoo_manager.verify("didReceiveUserDataProvider(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(currencyCode: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: currencyCode) { $0 }] + return cuckoo_manager.verify("didReceive(currencyCode: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppSearchInteractorOutputProtocolStub: DAppSearchInteractorOutputProtocol { + class SettingsInteractorOutputProtocolStub: SettingsInteractorOutputProtocol { @@ -20061,13 +18782,19 @@ import RobinHood - func didReceive(dAppsResult: Result) { + func didReceive(wallet: MetaAccountModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveFavorite(changes: [DataProviderChange]) { + func didReceiveUserDataProvider(error: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceive(currencyCode: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -20075,19 +18802,19 @@ import RobinHood - class MockDAppSearchWireframeProtocol: DAppSearchWireframeProtocol, Cuckoo.ProtocolMock { + class MockSettingsWireframeProtocol: SettingsWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = DAppSearchWireframeProtocol + typealias MocksType = SettingsWireframeProtocol - typealias Stubbing = __StubbingProxy_DAppSearchWireframeProtocol - typealias Verification = __VerificationProxy_DAppSearchWireframeProtocol + typealias Stubbing = __StubbingProxy_SettingsWireframeProtocol + typealias Verification = __VerificationProxy_SettingsWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: DAppSearchWireframeProtocol? + private var __defaultImplStub: SettingsWireframeProtocol? - func enableDefaultImplementation(_ stub: DAppSearchWireframeProtocol) { + func enableDefaultImplementation(_ stub: SettingsWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -20100,114 +18827,141 @@ import RobinHood - func close(from view: DAppSearchViewProtocol?) { + func showAccountDetails(for walletId: String, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("close(from: DAppSearchViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("showAccountDetails(for: String, from: ControllerBackedProtocol?)", + parameters: (walletId, view), + escapingParameters: (walletId, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(from: view)) + defaultCall: __defaultImplStub!.showAccountDetails(for: walletId, from: view)) } - - struct __StubbingProxy_DAppSearchWireframeProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func close(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppSearchViewProtocol?)> where M1.OptionalMatchedType == DAppSearchViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppSearchViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchWireframeProtocol.self, method: "close(from: DAppSearchViewProtocol?)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_DAppSearchWireframeProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func close(from view: M1) -> Cuckoo.__DoNotUse<(DAppSearchViewProtocol?), Void> where M1.OptionalMatchedType == DAppSearchViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(DAppSearchViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(from: DAppSearchViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class DAppSearchWireframeProtocolStub: DAppSearchWireframeProtocol { - - - - - - func close(from view: DAppSearchViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func showAccountSelection(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showAccountSelection(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showAccountSelection(from: view)) + } -} - - - - class MockDAppSearchDelegate: DAppSearchDelegate, Cuckoo.ProtocolMock { - - typealias MocksType = DAppSearchDelegate - typealias Stubbing = __StubbingProxy_DAppSearchDelegate - typealias Verification = __VerificationProxy_DAppSearchDelegate - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: DAppSearchDelegate? - - func enableDefaultImplementation(_ stub: DAppSearchDelegate) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func showLanguageSelection(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showLanguageSelection(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showLanguageSelection(from: view)) + } - - - - - - - func didCompleteDAppSearchResult(_ result: DAppSearchResult) { + func showPincodeChange(from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("didCompleteDAppSearchResult(_: DAppSearchResult)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("showPincodeChange(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didCompleteDAppSearchResult(result)) + defaultCall: __defaultImplStub!.showPincodeChange(from: view)) + + } + + + + func showCurrencies(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showCurrencies(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showCurrencies(from: view)) + + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + + } + + + + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + + return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", + parameters: (url, view, style), + escapingParameters: (url, view, style), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) + + } + + + + func presentSuccessNotification(_ title: String, from view: ControllerBackedProtocol?, completion closure: (() -> Void)?) { + + return cuckoo_manager.call("presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", + parameters: (title, view, closure), + escapingParameters: (title, view, closure), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentSuccessNotification(title, from: view, completion: closure)) } - struct __StubbingProxy_DAppSearchDelegate: Cuckoo.StubbingProxy { + struct __StubbingProxy_SettingsWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -20215,14 +18969,54 @@ import RobinHood } - func didCompleteDAppSearchResult(_ result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(DAppSearchResult)> where M1.MatchedType == DAppSearchResult { - let matchers: [Cuckoo.ParameterMatcher<(DAppSearchResult)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockDAppSearchDelegate.self, method: "didCompleteDAppSearchResult(_: DAppSearchResult)", parameterMatchers: matchers)) + func showAccountDetails(for walletId: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(String, ControllerBackedProtocol?)> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?)>] = [wrap(matchable: walletId) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showAccountDetails(for: String, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showAccountSelection(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showAccountSelection(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showLanguageSelection(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showLanguageSelection(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showPincodeChange(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showPincodeChange(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showCurrencies(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showCurrencies(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) + } + + func presentSuccessNotification(_ title: M1, from view: M2, completion closure: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(String, ControllerBackedProtocol?, (() -> Void)?)> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == (() -> Void) { + let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?, (() -> Void)?)>] = [wrap(matchable: title) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: closure) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_DAppSearchDelegate: Cuckoo.VerificationProxy { + struct __VerificationProxy_SettingsWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -20237,15 +19031,63 @@ import RobinHood @discardableResult - func didCompleteDAppSearchResult(_ result: M1) -> Cuckoo.__DoNotUse<(DAppSearchResult), Void> where M1.MatchedType == DAppSearchResult { - let matchers: [Cuckoo.ParameterMatcher<(DAppSearchResult)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didCompleteDAppSearchResult(_: DAppSearchResult)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showAccountDetails(for walletId: M1, from view: M2) -> Cuckoo.__DoNotUse<(String, ControllerBackedProtocol?), Void> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?)>] = [wrap(matchable: walletId) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("showAccountDetails(for: String, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showAccountSelection(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showAccountSelection(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showLanguageSelection(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showLanguageSelection(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showPincodeChange(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showPincodeChange(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showCurrencies(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showCurrencies(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentSuccessNotification(_ title: M1, from view: M2, completion closure: M3) -> Cuckoo.__DoNotUse<(String, ControllerBackedProtocol?, (() -> Void)?), Void> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == (() -> Void) { + let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?, (() -> Void)?)>] = [wrap(matchable: title) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: closure) { $0.2 }] + return cuckoo_manager.verify("presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class DAppSearchDelegateStub: DAppSearchDelegate { + class SettingsWireframeProtocolStub: SettingsWireframeProtocol { @@ -20253,7 +19095,55 @@ import RobinHood - func didCompleteDAppSearchResult(_ result: DAppSearchResult) { + func showAccountDetails(for walletId: String, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showAccountSelection(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showLanguageSelection(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showPincodeChange(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showCurrencies(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentSuccessNotification(_ title: String, from view: ControllerBackedProtocol?, completion closure: (() -> Void)?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -20263,23 +19153,22 @@ import RobinHood import Cuckoo @testable import novawallet -import Foundation import SoraFoundation - class MockAccountExportPasswordViewProtocol: AccountExportPasswordViewProtocol, Cuckoo.ProtocolMock { + class MockAnalyticsRewardDetailsViewProtocol: AnalyticsRewardDetailsViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = AccountExportPasswordViewProtocol + typealias MocksType = AnalyticsRewardDetailsViewProtocol - typealias Stubbing = __StubbingProxy_AccountExportPasswordViewProtocol - typealias Verification = __VerificationProxy_AccountExportPasswordViewProtocol + typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsViewProtocol + typealias Verification = __VerificationProxy_AnalyticsRewardDetailsViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: AccountExportPasswordViewProtocol? + private var __defaultImplStub: AnalyticsRewardDetailsViewProtocol? - func enableDefaultImplementation(_ stub: AccountExportPasswordViewProtocol) { + func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -20314,42 +19203,66 @@ import SoraFoundation } + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } + + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } + + } + - func setPasswordInputViewModel(_ viewModel: InputViewModelProtocol) { + func bind(viewModel: LocalizableResource) { - return cuckoo_manager.call("setPasswordInputViewModel(_: InputViewModelProtocol)", + return cuckoo_manager.call("bind(viewModel: LocalizableResource)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setPasswordInputViewModel(viewModel)) + defaultCall: __defaultImplStub!.bind(viewModel: viewModel)) } - func setPasswordConfirmationViewModel(_ viewModel: InputViewModelProtocol) { + public func applyLocalization() { - return cuckoo_manager.call("setPasswordConfirmationViewModel(_: InputViewModelProtocol)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setPasswordConfirmationViewModel(viewModel)) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_AccountExportPasswordViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_AnalyticsRewardDetailsViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -20357,29 +19270,34 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - func setPasswordInputViewModel(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(InputViewModelProtocol)> where M1.MatchedType == InputViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordViewProtocol.self, method: "setPasswordInputViewModel(_: InputViewModelProtocol)", parameterMatchers: matchers)) + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func setPasswordConfirmationViewModel(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(InputViewModelProtocol)> where M1.MatchedType == InputViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordViewProtocol.self, method: "setPasswordConfirmationViewModel(_: InputViewModelProtocol)", parameterMatchers: matchers)) + + func bind(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsViewProtocol.self, method: "bind(viewModel: LocalizableResource)", parameterMatchers: matchers)) + } + + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_AccountExportPasswordViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_AnalyticsRewardDetailsViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -20401,24 +19319,29 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func setPasswordInputViewModel(_ viewModel: M1) -> Cuckoo.__DoNotUse<(InputViewModelProtocol), Void> where M1.MatchedType == InputViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("setPasswordInputViewModel(_: InputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func bind(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("bind(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func setPasswordConfirmationViewModel(_ viewModel: M1) -> Cuckoo.__DoNotUse<(InputViewModelProtocol), Void> where M1.MatchedType == InputViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("setPasswordConfirmationViewModel(_: InputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class AccountExportPasswordViewProtocolStub: AccountExportPasswordViewProtocol { + class AnalyticsRewardDetailsViewProtocolStub: AnalyticsRewardDetailsViewProtocol { @@ -20437,6 +19360,17 @@ import SoraFoundation } } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } @@ -20444,13 +19378,13 @@ import SoraFoundation - func setPasswordInputViewModel(_ viewModel: InputViewModelProtocol) { + func bind(viewModel: LocalizableResource) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func setPasswordConfirmationViewModel(_ viewModel: InputViewModelProtocol) { + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -20458,19 +19392,19 @@ import SoraFoundation - class MockAccountExportPasswordPresenterProtocol: AccountExportPasswordPresenterProtocol, Cuckoo.ProtocolMock { + class MockAnalyticsRewardDetailsPresenterProtocol: AnalyticsRewardDetailsPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = AccountExportPasswordPresenterProtocol + typealias MocksType = AnalyticsRewardDetailsPresenterProtocol - typealias Stubbing = __StubbingProxy_AccountExportPasswordPresenterProtocol - typealias Verification = __VerificationProxy_AccountExportPasswordPresenterProtocol + typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsPresenterProtocol + typealias Verification = __VerificationProxy_AnalyticsRewardDetailsPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: AccountExportPasswordPresenterProtocol? + private var __defaultImplStub: AnalyticsRewardDetailsPresenterProtocol? - func enableDefaultImplementation(_ stub: AccountExportPasswordPresenterProtocol) { + func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -20498,21 +19432,21 @@ import SoraFoundation - func proceed() { + func handleEventIdAction() { - return cuckoo_manager.call("proceed()", + return cuckoo_manager.call("handleEventIdAction()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.handleEventIdAction()) } - struct __StubbingProxy_AccountExportPasswordPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_AnalyticsRewardDetailsPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -20522,17 +19456,17 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func handleEventIdAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsPresenterProtocol.self, method: "handleEventIdAction()", parameterMatchers: matchers)) } } - struct __VerificationProxy_AccountExportPasswordPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_AnalyticsRewardDetailsPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -20553,15 +19487,15 @@ import SoraFoundation } @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { + func handleEventIdAction() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("handleEventIdAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class AccountExportPasswordPresenterProtocolStub: AccountExportPasswordPresenterProtocol { + class AnalyticsRewardDetailsPresenterProtocolStub: AnalyticsRewardDetailsPresenterProtocol { @@ -20575,7 +19509,7 @@ import SoraFoundation - func proceed() { + func handleEventIdAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -20583,19 +19517,19 @@ import SoraFoundation - class MockAccountExportPasswordInteractorInputProtocol: AccountExportPasswordInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockAnalyticsRewardDetailsInteractorInputProtocol: AnalyticsRewardDetailsInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = AccountExportPasswordInteractorInputProtocol + typealias MocksType = AnalyticsRewardDetailsInteractorInputProtocol - typealias Stubbing = __StubbingProxy_AccountExportPasswordInteractorInputProtocol - typealias Verification = __VerificationProxy_AccountExportPasswordInteractorInputProtocol + typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsInteractorInputProtocol + typealias Verification = __VerificationProxy_AnalyticsRewardDetailsInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: AccountExportPasswordInteractorInputProtocol? + private var __defaultImplStub: AnalyticsRewardDetailsInteractorInputProtocol? - func enableDefaultImplementation(_ stub: AccountExportPasswordInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -20606,23 +19540,8 @@ import SoraFoundation - - - func exportAccount(password: String) { - - return cuckoo_manager.call("exportAccount(password: String)", - parameters: (password), - escapingParameters: (password), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.exportAccount(password: password)) - - } - - struct __StubbingProxy_AccountExportPasswordInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_AnalyticsRewardDetailsInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -20630,14 +19549,9 @@ import SoraFoundation } - func exportAccount(password: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: password) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordInteractorInputProtocol.self, method: "exportAccount(password: String)", parameterMatchers: matchers)) - } - } - struct __VerificationProxy_AccountExportPasswordInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_AnalyticsRewardDetailsInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -20651,44 +19565,32 @@ import SoraFoundation - @discardableResult - func exportAccount(password: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: password) { $0 }] - return cuckoo_manager.verify("exportAccount(password: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } - class AccountExportPasswordInteractorInputProtocolStub: AccountExportPasswordInteractorInputProtocol { + class AnalyticsRewardDetailsInteractorInputProtocolStub: AnalyticsRewardDetailsInteractorInputProtocol { - - - func exportAccount(password: String) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - } - class MockAccountExportPasswordInteractorOutputProtocol: AccountExportPasswordInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockAnalyticsRewardDetailsInteractorOutputProtocol: AnalyticsRewardDetailsInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = AccountExportPasswordInteractorOutputProtocol + typealias MocksType = AnalyticsRewardDetailsInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_AccountExportPasswordInteractorOutputProtocol - typealias Verification = __VerificationProxy_AccountExportPasswordInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsInteractorOutputProtocol + typealias Verification = __VerificationProxy_AnalyticsRewardDetailsInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: AccountExportPasswordInteractorOutputProtocol? + private var __defaultImplStub: AnalyticsRewardDetailsInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: AccountExportPasswordInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -20699,38 +19601,8 @@ import SoraFoundation - - - func didExport(json: RestoreJson) { - - return cuckoo_manager.call("didExport(json: RestoreJson)", - parameters: (json), - escapingParameters: (json), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didExport(json: json)) - - } - - - - func didReceive(error: Error) { - - return cuckoo_manager.call("didReceive(error: Error)", - parameters: (error), - escapingParameters: (error), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(error: error)) - - } - - struct __StubbingProxy_AccountExportPasswordInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_AnalyticsRewardDetailsInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -20738,19 +19610,9 @@ import SoraFoundation } - func didExport(json: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RestoreJson)> where M1.MatchedType == RestoreJson { - let matchers: [Cuckoo.ParameterMatcher<(RestoreJson)>] = [wrap(matchable: json) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordInteractorOutputProtocol.self, method: "didExport(json: RestoreJson)", parameterMatchers: matchers)) - } - - func didReceive(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordInteractorOutputProtocol.self, method: "didReceive(error: Error)", parameterMatchers: matchers)) - } - } - struct __VerificationProxy_AccountExportPasswordInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_AnalyticsRewardDetailsInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -20764,56 +19626,32 @@ import SoraFoundation - @discardableResult - func didExport(json: M1) -> Cuckoo.__DoNotUse<(RestoreJson), Void> where M1.MatchedType == RestoreJson { - let matchers: [Cuckoo.ParameterMatcher<(RestoreJson)>] = [wrap(matchable: json) { $0 }] - return cuckoo_manager.verify("didExport(json: RestoreJson)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return cuckoo_manager.verify("didReceive(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } - class AccountExportPasswordInteractorOutputProtocolStub: AccountExportPasswordInteractorOutputProtocol { + class AnalyticsRewardDetailsInteractorOutputProtocolStub: AnalyticsRewardDetailsInteractorOutputProtocol { - - - func didExport(json: RestoreJson) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(error: Error) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - } - class MockAccountExportPasswordWireframeProtocol: AccountExportPasswordWireframeProtocol, Cuckoo.ProtocolMock { + class MockAnalyticsRewardDetailsWireframeProtocol: AnalyticsRewardDetailsWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = AccountExportPasswordWireframeProtocol + typealias MocksType = AnalyticsRewardDetailsWireframeProtocol - typealias Stubbing = __StubbingProxy_AccountExportPasswordWireframeProtocol - typealias Verification = __VerificationProxy_AccountExportPasswordWireframeProtocol + typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsWireframeProtocol + typealias Verification = __VerificationProxy_AnalyticsRewardDetailsWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: AccountExportPasswordWireframeProtocol? + private var __defaultImplStub: AnalyticsRewardDetailsWireframeProtocol? - func enableDefaultImplementation(_ stub: AccountExportPasswordWireframeProtocol) { + func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -20826,16 +19664,16 @@ import SoraFoundation - func showJSONExport(_ json: RestoreJson, from view: AccountExportPasswordViewProtocol?) { + func presentSuccessNotification(_ title: String, from view: ControllerBackedProtocol?, completion closure: (() -> Void)?) { - return cuckoo_manager.call("showJSONExport(_: RestoreJson, from: AccountExportPasswordViewProtocol?)", - parameters: (json, view), - escapingParameters: (json, view), + return cuckoo_manager.call("presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", + parameters: (title, view, closure), + escapingParameters: (title, view, closure), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showJSONExport(json, from: view)) + defaultCall: __defaultImplStub!.presentSuccessNotification(title, from: view, completion: closure)) } @@ -20869,8 +19707,23 @@ import SoraFoundation } + + + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + + return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", + parameters: (url, view, style), + escapingParameters: (url, view, style), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) + + } + - struct __StubbingProxy_AccountExportPasswordWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_AnalyticsRewardDetailsWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -20878,24 +19731,29 @@ import SoraFoundation } - func showJSONExport(_ json: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(RestoreJson, AccountExportPasswordViewProtocol?)> where M1.MatchedType == RestoreJson, M2.OptionalMatchedType == AccountExportPasswordViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(RestoreJson, AccountExportPasswordViewProtocol?)>] = [wrap(matchable: json) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordWireframeProtocol.self, method: "showJSONExport(_: RestoreJson, from: AccountExportPasswordViewProtocol?)", parameterMatchers: matchers)) + func presentSuccessNotification(_ title: M1, from view: M2, completion closure: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(String, ControllerBackedProtocol?, (() -> Void)?)> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == (() -> Void) { + let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?, (() -> Void)?)>] = [wrap(matchable: title) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: closure) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsWireframeProtocol.self, method: "presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockAccountExportPasswordWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) } } - struct __VerificationProxy_AccountExportPasswordWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_AnalyticsRewardDetailsWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -20910,9 +19768,9 @@ import SoraFoundation @discardableResult - func showJSONExport(_ json: M1, from view: M2) -> Cuckoo.__DoNotUse<(RestoreJson, AccountExportPasswordViewProtocol?), Void> where M1.MatchedType == RestoreJson, M2.OptionalMatchedType == AccountExportPasswordViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(RestoreJson, AccountExportPasswordViewProtocol?)>] = [wrap(matchable: json) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("showJSONExport(_: RestoreJson, from: AccountExportPasswordViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentSuccessNotification(_ title: M1, from view: M2, completion closure: M3) -> Cuckoo.__DoNotUse<(String, ControllerBackedProtocol?, (() -> Void)?), Void> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == (() -> Void) { + let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?, (() -> Void)?)>] = [wrap(matchable: title) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: closure) { $0.2 }] + return cuckoo_manager.verify("presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -20927,10 +19785,16 @@ import SoraFoundation return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } - class AccountExportPasswordWireframeProtocolStub: AccountExportPasswordWireframeProtocol { + class AnalyticsRewardDetailsWireframeProtocolStub: AnalyticsRewardDetailsWireframeProtocol { @@ -20938,7 +19802,7 @@ import SoraFoundation - func showJSONExport(_ json: RestoreJson, from view: AccountExportPasswordViewProtocol?) { + func presentSuccessNotification(_ title: String, from view: ControllerBackedProtocol?, completion closure: (() -> Void)?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -20954,29 +19818,127 @@ import SoraFoundation return DefaultValueRegistry.defaultValue(for: (Void).self) } + + + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + + + class MockAnalyticsRewardDetailsViewModelFactoryProtocol: AnalyticsRewardDetailsViewModelFactoryProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = AnalyticsRewardDetailsViewModelFactoryProtocol + + typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsViewModelFactoryProtocol + typealias Verification = __VerificationProxy_AnalyticsRewardDetailsViewModelFactoryProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: AnalyticsRewardDetailsViewModelFactoryProtocol? + + func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsViewModelFactoryProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + + + + + + + + + func createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource { + + return cuckoo_manager.call("createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource", + parameters: (rewardModel), + escapingParameters: (rewardModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.createViweModel(rewardModel: rewardModel)) + + } + + + struct __StubbingProxy_AnalyticsRewardDetailsViewModelFactoryProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func createViweModel(rewardModel: M1) -> Cuckoo.ProtocolStubFunction<(AnalyticsRewardDetailsModel), LocalizableResource> where M1.MatchedType == AnalyticsRewardDetailsModel { + let matchers: [Cuckoo.ParameterMatcher<(AnalyticsRewardDetailsModel)>] = [wrap(matchable: rewardModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsViewModelFactoryProtocol.self, method: "createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_AnalyticsRewardDetailsViewModelFactoryProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func createViweModel(rewardModel: M1) -> Cuckoo.__DoNotUse<(AnalyticsRewardDetailsModel), LocalizableResource> where M1.MatchedType == AnalyticsRewardDetailsModel { + let matchers: [Cuckoo.ParameterMatcher<(AnalyticsRewardDetailsModel)>] = [wrap(matchable: rewardModel) { $0 }] + return cuckoo_manager.verify("createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class AnalyticsRewardDetailsViewModelFactoryProtocolStub: AnalyticsRewardDetailsViewModelFactoryProtocol { + + + + + + + + func createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource { + return DefaultValueRegistry.defaultValue(for: (LocalizableResource).self) + } + } import Cuckoo @testable import novawallet -import Foundation import SoraFoundation - class MockExportGenericViewProtocol: ExportGenericViewProtocol, Cuckoo.ProtocolMock { + class MockControllerAccountViewProtocol: ControllerAccountViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ExportGenericViewProtocol + typealias MocksType = ControllerAccountViewProtocol - typealias Stubbing = __StubbingProxy_ExportGenericViewProtocol - typealias Verification = __VerificationProxy_ExportGenericViewProtocol + typealias Stubbing = __StubbingProxy_ControllerAccountViewProtocol + typealias Verification = __VerificationProxy_ControllerAccountViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ExportGenericViewProtocol? + private var __defaultImplStub: ControllerAccountViewProtocol? - func enableDefaultImplementation(_ stub: ExportGenericViewProtocol) { + func enableDefaultImplementation(_ stub: ControllerAccountViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -21011,27 +19973,81 @@ import SoraFoundation } + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } + + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } + + } + - func set(viewModel: ExportGenericViewModel) { + func reload(with viewModel: ControllerAccountViewModel) { - return cuckoo_manager.call("set(viewModel: ExportGenericViewModel)", + return cuckoo_manager.call("reload(with: ControllerAccountViewModel)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.set(viewModel: viewModel)) + defaultCall: __defaultImplStub!.reload(with: viewModel)) + + } + + + + func didCompleteControllerSelection() { + + return cuckoo_manager.call("didCompleteControllerSelection()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didCompleteControllerSelection()) + + } + + + + public func applyLocalization() { + + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_ExportGenericViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ControllerAccountViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -21039,24 +20055,39 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - func set(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewModel)> where M1.MatchedType == ExportGenericViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportGenericViewProtocol.self, method: "set(viewModel: ExportGenericViewModel)", parameterMatchers: matchers)) + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") + } + + + func reload(with viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerAccountViewModel)> where M1.MatchedType == ControllerAccountViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ControllerAccountViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountViewProtocol.self, method: "reload(with: ControllerAccountViewModel)", parameterMatchers: matchers)) + } + + func didCompleteControllerSelection() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountViewProtocol.self, method: "didCompleteControllerSelection()", parameterMatchers: matchers)) + } + + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_ExportGenericViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ControllerAccountViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -21078,18 +20109,35 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func set(viewModel: M1) -> Cuckoo.__DoNotUse<(ExportGenericViewModel), Void> where M1.MatchedType == ExportGenericViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("set(viewModel: ExportGenericViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload(with viewModel: M1) -> Cuckoo.__DoNotUse<(ControllerAccountViewModel), Void> where M1.MatchedType == ControllerAccountViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ControllerAccountViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("reload(with: ControllerAccountViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didCompleteControllerSelection() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didCompleteControllerSelection()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ExportGenericViewProtocolStub: ExportGenericViewProtocol { + class ControllerAccountViewProtocolStub: ControllerAccountViewProtocol { @@ -21108,6 +20156,17 @@ import SoraFoundation } } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } @@ -21115,7 +20174,19 @@ import SoraFoundation - func set(viewModel: ExportGenericViewModel) { + func reload(with viewModel: ControllerAccountViewModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didCompleteControllerSelection() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -21123,19 +20194,19 @@ import SoraFoundation - class MockExportGenericPresenterProtocol: ExportGenericPresenterProtocol, Cuckoo.ProtocolMock { + class MockControllerAccountViewModelFactoryProtocol: ControllerAccountViewModelFactoryProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ExportGenericPresenterProtocol + typealias MocksType = ControllerAccountViewModelFactoryProtocol - typealias Stubbing = __StubbingProxy_ExportGenericPresenterProtocol - typealias Verification = __VerificationProxy_ExportGenericPresenterProtocol + typealias Stubbing = __StubbingProxy_ControllerAccountViewModelFactoryProtocol + typealias Verification = __VerificationProxy_ControllerAccountViewModelFactoryProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ExportGenericPresenterProtocol? + private var __defaultImplStub: ControllerAccountViewModelFactoryProtocol? - func enableDefaultImplementation(_ stub: ExportGenericPresenterProtocol) { + func enableDefaultImplementation(_ stub: ControllerAccountViewModelFactoryProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -21148,51 +20219,21 @@ import SoraFoundation - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - - } - - - - func activateExport() { - - return cuckoo_manager.call("activateExport()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.activateExport()) - - } - - - - func activateAdvancedSettings() { + func createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel { - return cuckoo_manager.call("activateAdvancedSettings()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel", + parameters: (stashItem, stashAccountItem, chosenAccountItem), + escapingParameters: (stashItem, stashAccountItem, chosenAccountItem), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activateAdvancedSettings()) + defaultCall: __defaultImplStub!.createViewModel(stashItem: stashItem, stashAccountItem: stashAccountItem, chosenAccountItem: chosenAccountItem)) } - struct __StubbingProxy_ExportGenericPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ControllerAccountViewModelFactoryProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -21200,24 +20241,14 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockExportGenericPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func activateExport() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockExportGenericPresenterProtocol.self, method: "activateExport()", parameterMatchers: matchers)) - } - - func activateAdvancedSettings() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockExportGenericPresenterProtocol.self, method: "activateAdvancedSettings()", parameterMatchers: matchers)) + func createViewModel(stashItem: M1, stashAccountItem: M2, chosenAccountItem: M3) -> Cuckoo.ProtocolStubFunction<(StashItem, MetaChainAccountResponse?, MetaChainAccountResponse?), ControllerAccountViewModel> where M1.MatchedType == StashItem, M2.OptionalMatchedType == MetaChainAccountResponse, M3.OptionalMatchedType == MetaChainAccountResponse { + let matchers: [Cuckoo.ParameterMatcher<(StashItem, MetaChainAccountResponse?, MetaChainAccountResponse?)>] = [wrap(matchable: stashItem) { $0.0 }, wrap(matchable: stashAccountItem) { $0.1 }, wrap(matchable: chosenAccountItem) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountViewModelFactoryProtocol.self, method: "createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel", parameterMatchers: matchers)) } } - struct __VerificationProxy_ExportGenericPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ControllerAccountViewModelFactoryProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -21232,27 +20263,15 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func activateExport() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateExport()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func activateAdvancedSettings() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateAdvancedSettings()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func createViewModel(stashItem: M1, stashAccountItem: M2, chosenAccountItem: M3) -> Cuckoo.__DoNotUse<(StashItem, MetaChainAccountResponse?, MetaChainAccountResponse?), ControllerAccountViewModel> where M1.MatchedType == StashItem, M2.OptionalMatchedType == MetaChainAccountResponse, M3.OptionalMatchedType == MetaChainAccountResponse { + let matchers: [Cuckoo.ParameterMatcher<(StashItem, MetaChainAccountResponse?, MetaChainAccountResponse?)>] = [wrap(matchable: stashItem) { $0.0 }, wrap(matchable: stashAccountItem) { $0.1 }, wrap(matchable: chosenAccountItem) { $0.2 }] + return cuckoo_manager.verify("createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ExportGenericPresenterProtocolStub: ExportGenericPresenterProtocol { + class ControllerAccountViewModelFactoryProtocolStub: ControllerAccountViewModelFactoryProtocol { @@ -21260,39 +20279,27 @@ import SoraFoundation - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func activateExport() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func activateAdvancedSettings() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel { + return DefaultValueRegistry.defaultValue(for: (ControllerAccountViewModel).self) } } - class MockExportGenericWireframeProtocol: ExportGenericWireframeProtocol, Cuckoo.ProtocolMock { + class MockControllerAccountPresenterProtocol: ControllerAccountPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ExportGenericWireframeProtocol + typealias MocksType = ControllerAccountPresenterProtocol - typealias Stubbing = __StubbingProxy_ExportGenericWireframeProtocol - typealias Verification = __VerificationProxy_ExportGenericWireframeProtocol + typealias Stubbing = __StubbingProxy_ControllerAccountPresenterProtocol + typealias Verification = __VerificationProxy_ControllerAccountPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ExportGenericWireframeProtocol? + private var __defaultImplStub: ControllerAccountPresenterProtocol? - func enableDefaultImplementation(_ stub: ExportGenericWireframeProtocol) { + func enableDefaultImplementation(_ stub: ControllerAccountPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -21305,81 +20312,81 @@ import SoraFoundation - func close(view: ExportGenericViewProtocol?) { + func setup() { - return cuckoo_manager.call("close(view: ExportGenericViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(view: view)) + defaultCall: __defaultImplStub!.setup()) } - func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + func handleStashAction() { - return cuckoo_manager.call("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", - parameters: (view, secretSource, settings), - escapingParameters: (view, secretSource, settings), + return cuckoo_manager.call("handleStashAction()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showAdvancedSettings(from: view, secretSource: secretSource, settings: settings)) + defaultCall: __defaultImplStub!.handleStashAction()) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func handleControllerAction() { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("handleControllerAction()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.handleControllerAction()) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func selectLearnMore() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("selectLearnMore()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.selectLearnMore()) } - func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + func proceed() { - return cuckoo_manager.call("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", - parameters: (source, view, completionHandler), - escapingParameters: (source, view, completionHandler), + return cuckoo_manager.call("proceed()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.share(source: source, from: view, with: completionHandler)) + defaultCall: __defaultImplStub!.proceed()) } - struct __StubbingProxy_ExportGenericWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ControllerAccountPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -21387,34 +20394,34 @@ import SoraFoundation } - func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?)> where M1.OptionalMatchedType == ExportGenericViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "close(view: ExportGenericViewProtocol?)", parameterMatchers: matchers)) - } - - func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func handleStashAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "handleStashAction()", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func handleControllerAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "handleControllerAction()", parameterMatchers: matchers)) } - func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { - let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportGenericWireframeProtocol.self, method: "share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", parameterMatchers: matchers)) + func selectLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "selectLearnMore()", parameterMatchers: matchers)) + } + + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } } - struct __VerificationProxy_ExportGenericWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ControllerAccountPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -21429,39 +20436,39 @@ import SoraFoundation @discardableResult - func close(view: M1) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(view: ExportGenericViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] - return cuckoo_manager.verify("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func handleStashAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("handleStashAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func handleControllerAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("handleControllerAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectLearnMore() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.__DoNotUse<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?), Void> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { - let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] - return cuckoo_manager.verify("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceed() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ExportGenericWireframeProtocolStub: ExportGenericWireframeProtocol { + class ControllerAccountPresenterProtocolStub: ControllerAccountPresenterProtocol { @@ -21469,56 +20476,51 @@ import SoraFoundation - func close(view: ExportGenericViewProtocol?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + func handleStashAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func handleControllerAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func selectLearnMore() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + func proceed() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import IrohaCrypto - - class MockExportMnemonicInteractorInputProtocol: ExportMnemonicInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockControllerAccountInteractorInputProtocol: ControllerAccountInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ExportMnemonicInteractorInputProtocol + typealias MocksType = ControllerAccountInteractorInputProtocol - typealias Stubbing = __StubbingProxy_ExportMnemonicInteractorInputProtocol - typealias Verification = __VerificationProxy_ExportMnemonicInteractorInputProtocol + typealias Stubbing = __StubbingProxy_ControllerAccountInteractorInputProtocol + typealias Verification = __VerificationProxy_ControllerAccountInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ExportMnemonicInteractorInputProtocol? + private var __defaultImplStub: ControllerAccountInteractorInputProtocol? - func enableDefaultImplementation(_ stub: ExportMnemonicInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: ControllerAccountInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -21531,129 +20533,66 @@ import IrohaCrypto - func fetchExportData() { + func setup() { - return cuckoo_manager.call("fetchExportData()", + return cuckoo_manager.call("setup()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.fetchExportData()) + defaultCall: __defaultImplStub!.setup()) } - - struct __StubbingProxy_ExportMnemonicInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func fetchExportData() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicInteractorInputProtocol.self, method: "fetchExportData()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ExportMnemonicInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func fetchExportData() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("fetchExportData()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class ExportMnemonicInteractorInputProtocolStub: ExportMnemonicInteractorInputProtocol { - - - - - - - - func fetchExportData() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - - - class MockExportMnemonicInteractorOutputProtocol: ExportMnemonicInteractorOutputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ExportMnemonicInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_ExportMnemonicInteractorOutputProtocol - typealias Verification = __VerificationProxy_ExportMnemonicInteractorOutputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ExportMnemonicInteractorOutputProtocol? - - func enableDefaultImplementation(_ stub: ExportMnemonicInteractorOutputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func estimateFee(for account: ChainAccountResponse) { + + return cuckoo_manager.call("estimateFee(for: ChainAccountResponse)", + parameters: (account), + escapingParameters: (account), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.estimateFee(for: account)) + } - - - - - - - func didReceive(exportData: ExportMnemonicData) { + func fetchLedger(controllerAddress: AccountAddress) { - return cuckoo_manager.call("didReceive(exportData: ExportMnemonicData)", - parameters: (exportData), - escapingParameters: (exportData), + return cuckoo_manager.call("fetchLedger(controllerAddress: AccountAddress)", + parameters: (controllerAddress), + escapingParameters: (controllerAddress), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(exportData: exportData)) + defaultCall: __defaultImplStub!.fetchLedger(controllerAddress: controllerAddress)) } - func didReceive(error: Error) { + func fetchControllerAccountInfo(controllerAddress: AccountAddress) { - return cuckoo_manager.call("didReceive(error: Error)", - parameters: (error), - escapingParameters: (error), + return cuckoo_manager.call("fetchControllerAccountInfo(controllerAddress: AccountAddress)", + parameters: (controllerAddress), + escapingParameters: (controllerAddress), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(error: error)) + defaultCall: __defaultImplStub!.fetchControllerAccountInfo(controllerAddress: controllerAddress)) } - struct __StubbingProxy_ExportMnemonicInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ControllerAccountInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -21661,19 +20600,29 @@ import IrohaCrypto } - func didReceive(exportData: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportMnemonicData)> where M1.MatchedType == ExportMnemonicData { - let matchers: [Cuckoo.ParameterMatcher<(ExportMnemonicData)>] = [wrap(matchable: exportData) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicInteractorOutputProtocol.self, method: "didReceive(exportData: ExportMnemonicData)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func didReceive(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicInteractorOutputProtocol.self, method: "didReceive(error: Error)", parameterMatchers: matchers)) + func estimateFee(for account: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainAccountResponse)> where M1.MatchedType == ChainAccountResponse { + let matchers: [Cuckoo.ParameterMatcher<(ChainAccountResponse)>] = [wrap(matchable: account) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorInputProtocol.self, method: "estimateFee(for: ChainAccountResponse)", parameterMatchers: matchers)) + } + + func fetchLedger(controllerAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: controllerAddress) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorInputProtocol.self, method: "fetchLedger(controllerAddress: AccountAddress)", parameterMatchers: matchers)) + } + + func fetchControllerAccountInfo(controllerAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: controllerAddress) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorInputProtocol.self, method: "fetchControllerAccountInfo(controllerAddress: AccountAddress)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ExportMnemonicInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ControllerAccountInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -21688,21 +20637,33 @@ import IrohaCrypto @discardableResult - func didReceive(exportData: M1) -> Cuckoo.__DoNotUse<(ExportMnemonicData), Void> where M1.MatchedType == ExportMnemonicData { - let matchers: [Cuckoo.ParameterMatcher<(ExportMnemonicData)>] = [wrap(matchable: exportData) { $0 }] - return cuckoo_manager.verify("didReceive(exportData: ExportMnemonicData)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return cuckoo_manager.verify("didReceive(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee(for account: M1) -> Cuckoo.__DoNotUse<(ChainAccountResponse), Void> where M1.MatchedType == ChainAccountResponse { + let matchers: [Cuckoo.ParameterMatcher<(ChainAccountResponse)>] = [wrap(matchable: account) { $0 }] + return cuckoo_manager.verify("estimateFee(for: ChainAccountResponse)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func fetchLedger(controllerAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: controllerAddress) { $0 }] + return cuckoo_manager.verify("fetchLedger(controllerAddress: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func fetchControllerAccountInfo(controllerAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: controllerAddress) { $0 }] + return cuckoo_manager.verify("fetchControllerAccountInfo(controllerAddress: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ExportMnemonicInteractorOutputProtocolStub: ExportMnemonicInteractorOutputProtocol { + class ControllerAccountInteractorInputProtocolStub: ControllerAccountInteractorInputProtocol { @@ -21710,13 +20671,25 @@ import IrohaCrypto - func didReceive(exportData: ExportMnemonicData) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(error: Error) { + func estimateFee(for account: ChainAccountResponse) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func fetchLedger(controllerAddress: AccountAddress) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func fetchControllerAccountInfo(controllerAddress: AccountAddress) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -21724,19 +20697,19 @@ import IrohaCrypto - class MockExportMnemonicWireframeProtocol: ExportMnemonicWireframeProtocol, Cuckoo.ProtocolMock { + class MockControllerAccountInteractorOutputProtocol: ControllerAccountInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ExportMnemonicWireframeProtocol + typealias MocksType = ControllerAccountInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_ExportMnemonicWireframeProtocol - typealias Verification = __VerificationProxy_ExportMnemonicWireframeProtocol + typealias Stubbing = __StubbingProxy_ControllerAccountInteractorOutputProtocol + typealias Verification = __VerificationProxy_ControllerAccountInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ExportMnemonicWireframeProtocol? + private var __defaultImplStub: ControllerAccountInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: ExportMnemonicWireframeProtocol) { + func enableDefaultImplementation(_ stub: ControllerAccountInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -21749,96 +20722,126 @@ import IrohaCrypto - func openConfirmationForMnemonic(_ mnemonic: IRMnemonicProtocol, from view: ExportGenericViewProtocol?) { + func didReceiveStashItem(result: Result) { - return cuckoo_manager.call("openConfirmationForMnemonic(_: IRMnemonicProtocol, from: ExportGenericViewProtocol?)", - parameters: (mnemonic, view), - escapingParameters: (mnemonic, view), + return cuckoo_manager.call("didReceiveStashItem(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.openConfirmationForMnemonic(mnemonic, from: view)) + defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) } - func close(view: ExportGenericViewProtocol?) { + func didReceiveStashAccount(result: Result) { - return cuckoo_manager.call("close(view: ExportGenericViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceiveStashAccount(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(view: view)) + defaultCall: __defaultImplStub!.didReceiveStashAccount(result: result)) } - func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + func didReceiveControllerAccount(result: Result) { - return cuckoo_manager.call("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", - parameters: (view, secretSource, settings), - escapingParameters: (view, secretSource, settings), + return cuckoo_manager.call("didReceiveControllerAccount(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showAdvancedSettings(from: view, secretSource: secretSource, settings: settings)) + defaultCall: __defaultImplStub!.didReceiveControllerAccount(result: result)) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.didReceiveAccounts(result: result)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didReceiveFee(result: Result) { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + func didReceiveControllerAccountInfo(result: Result, address: AccountAddress) { - return cuckoo_manager.call("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", - parameters: (source, view, completionHandler), - escapingParameters: (source, view, completionHandler), + return cuckoo_manager.call("didReceiveControllerAccountInfo(result: Result, address: AccountAddress)", + parameters: (result, address), + escapingParameters: (result, address), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.share(source: source, from: view, with: completionHandler)) + defaultCall: __defaultImplStub!.didReceiveControllerAccountInfo(result: result, address: address)) + + } + + + + func didReceiveAccountInfo(result: Result, address: AccountAddress) { + + return cuckoo_manager.call("didReceiveAccountInfo(result: Result, address: AccountAddress)", + parameters: (result, address), + escapingParameters: (result, address), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result, address: address)) + + } + + + + func didReceiveStakingLedger(result: Result) { + + return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) } - struct __StubbingProxy_ExportMnemonicWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ControllerAccountInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -21846,39 +20849,49 @@ import IrohaCrypto } - func openConfirmationForMnemonic(_ mnemonic: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(IRMnemonicProtocol, ExportGenericViewProtocol?)> where M1.MatchedType == IRMnemonicProtocol, M2.OptionalMatchedType == ExportGenericViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(IRMnemonicProtocol, ExportGenericViewProtocol?)>] = [wrap(matchable: mnemonic) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "openConfirmationForMnemonic(_: IRMnemonicProtocol, from: ExportGenericViewProtocol?)", parameterMatchers: matchers)) + func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) } - func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?)> where M1.OptionalMatchedType == ExportGenericViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "close(view: ExportGenericViewProtocol?)", parameterMatchers: matchers)) + func didReceiveStashAccount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveStashAccount(result: Result)", parameterMatchers: matchers)) } - func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", parameterMatchers: matchers)) + func didReceiveControllerAccount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveControllerAccount(result: Result)", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveAccounts(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[MetaChainAccountResponse], Error>)> where M1.MatchedType == Result<[MetaChainAccountResponse], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[MetaChainAccountResponse], Error>)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } - func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { - let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportMnemonicWireframeProtocol.self, method: "share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", parameterMatchers: matchers)) + func didReceiveControllerAccountInfo(result: M1, address: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Result, AccountAddress)> where M1.MatchedType == Result, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(Result, AccountAddress)>] = [wrap(matchable: result) { $0.0 }, wrap(matchable: address) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveControllerAccountInfo(result: Result, address: AccountAddress)", parameterMatchers: matchers)) + } + + func didReceiveAccountInfo(result: M1, address: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Result, AccountAddress)> where M1.MatchedType == Result, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(Result, AccountAddress)>] = [wrap(matchable: result) { $0.0 }, wrap(matchable: address) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result, address: AccountAddress)", parameterMatchers: matchers)) + } + + func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ExportMnemonicWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ControllerAccountInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -21893,45 +20906,57 @@ import IrohaCrypto @discardableResult - func openConfirmationForMnemonic(_ mnemonic: M1, from view: M2) -> Cuckoo.__DoNotUse<(IRMnemonicProtocol, ExportGenericViewProtocol?), Void> where M1.MatchedType == IRMnemonicProtocol, M2.OptionalMatchedType == ExportGenericViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(IRMnemonicProtocol, ExportGenericViewProtocol?)>] = [wrap(matchable: mnemonic) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("openConfirmationForMnemonic(_: IRMnemonicProtocol, from: ExportGenericViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func close(view: M1) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(view: ExportGenericViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStashAccount(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashAccount(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] - return cuckoo_manager.verify("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveControllerAccount(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveControllerAccount(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccounts(result: M1) -> Cuckoo.__DoNotUse<(Result<[MetaChainAccountResponse], Error>), Void> where M1.MatchedType == Result<[MetaChainAccountResponse], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[MetaChainAccountResponse], Error>)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.__DoNotUse<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?), Void> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { - let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] - return cuckoo_manager.verify("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveControllerAccountInfo(result: M1, address: M2) -> Cuckoo.__DoNotUse<(Result, AccountAddress), Void> where M1.MatchedType == Result, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(Result, AccountAddress)>] = [wrap(matchable: result) { $0.0 }, wrap(matchable: address) { $0.1 }] + return cuckoo_manager.verify("didReceiveControllerAccountInfo(result: Result, address: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveAccountInfo(result: M1, address: M2) -> Cuckoo.__DoNotUse<(Result, AccountAddress), Void> where M1.MatchedType == Result, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(Result, AccountAddress)>] = [wrap(matchable: result) { $0.0 }, wrap(matchable: address) { $0.1 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result, address: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ExportMnemonicWireframeProtocolStub: ExportMnemonicWireframeProtocol { + class ControllerAccountInteractorOutputProtocolStub: ControllerAccountInteractorOutputProtocol { @@ -21939,62 +20964,69 @@ import IrohaCrypto - func openConfirmationForMnemonic(_ mnemonic: IRMnemonicProtocol, from view: ExportGenericViewProtocol?) { + func didReceiveStashItem(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func close(view: ExportGenericViewProtocol?) { + func didReceiveStashAccount(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + func didReceiveControllerAccount(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didReceiveFee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + func didReceiveControllerAccountInfo(result: Result, address: AccountAddress) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveAccountInfo(result: Result, address: AccountAddress) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveStakingLedger(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import Foundation - - class MockExportRestoreJsonWireframeProtocol: ExportRestoreJsonWireframeProtocol, Cuckoo.ProtocolMock { + class MockControllerAccountWireframeProtocol: ControllerAccountWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ExportRestoreJsonWireframeProtocol + typealias MocksType = ControllerAccountWireframeProtocol - typealias Stubbing = __StubbingProxy_ExportRestoreJsonWireframeProtocol - typealias Verification = __VerificationProxy_ExportRestoreJsonWireframeProtocol + typealias Stubbing = __StubbingProxy_ControllerAccountWireframeProtocol + typealias Verification = __VerificationProxy_ControllerAccountWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ExportRestoreJsonWireframeProtocol? + private var __defaultImplStub: ControllerAccountWireframeProtocol? - func enableDefaultImplementation(_ stub: ExportRestoreJsonWireframeProtocol) { + func enableDefaultImplementation(_ stub: ControllerAccountWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -22007,81 +21039,96 @@ import Foundation - func close(view: ExportGenericViewProtocol?) { + func showConfirmation(from view: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse) { - return cuckoo_manager.call("close(view: ExportGenericViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("showConfirmation(from: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse)", + parameters: (view, controllerAccountItem), + escapingParameters: (view, controllerAccountItem), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(view: view)) + defaultCall: __defaultImplStub!.showConfirmation(from: view, controllerAccountItem: controllerAccountItem)) } - func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + func close(view: ControllerBackedProtocol?) { - return cuckoo_manager.call("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", - parameters: (view, secretSource, settings), - escapingParameters: (view, secretSource, settings), + return cuckoo_manager.call("close(view: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showAdvancedSettings(from: view, secretSource: secretSource, settings: settings)) + defaultCall: __defaultImplStub!.close(view: view)) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", + parameters: (url, view, style), + escapingParameters: (url, view, style), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func presentAccountSelection(_ accounts: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from view: ControllerBackedProtocol?, context: AnyObject?) { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", + parameters: (accounts, selectedAccountItem, title, delegate, view, context), + escapingParameters: (accounts, selectedAccountItem, title, delegate, view, context), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.presentAccountSelection(accounts, selectedAccountItem: selectedAccountItem, title: title, delegate: delegate, from: view, context: context)) } - func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", - parameters: (source, view, completionHandler), - escapingParameters: (source, view, completionHandler), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.share(source: source, from: view, with: completionHandler)) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_ExportRestoreJsonWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ControllerAccountWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -22089,34 +21136,39 @@ import Foundation } - func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?)> where M1.OptionalMatchedType == ExportGenericViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "close(view: ExportGenericViewProtocol?)", parameterMatchers: matchers)) + func showConfirmation(from view: M1, controllerAccountItem: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, MetaChainAccountResponse)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaChainAccountResponse { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaChainAccountResponse)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: controllerAccountItem) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "showConfirmation(from: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse)", parameterMatchers: matchers)) } - func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", parameterMatchers: matchers)) + func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "close(view: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) + } + + func presentAccountSelection(_ accounts: M1, selectedAccountItem: M2, title: M3, delegate: M4, from view: M5, context: M6) -> Cuckoo.ProtocolStubNoReturnFunction<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)> where M1.MatchedType == [MetaChainAccountResponse], M2.OptionalMatchedType == MetaChainAccountResponse, M3.MatchedType == LocalizableResource, M4.MatchedType == ModalPickerViewControllerDelegate, M5.OptionalMatchedType == ControllerBackedProtocol, M6.OptionalMatchedType == AnyObject { + let matchers: [Cuckoo.ParameterMatcher<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)>] = [wrap(matchable: accounts) { $0.0 }, wrap(matchable: selectedAccountItem) { $0.1 }, wrap(matchable: title) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: view) { $0.4 }, wrap(matchable: context) { $0.5 }] + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { - let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockExportRestoreJsonWireframeProtocol.self, method: "share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ExportRestoreJsonWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ControllerAccountWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -22131,15 +21183,27 @@ import Foundation @discardableResult - func close(view: M1) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(view: ExportGenericViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showConfirmation(from view: M1, controllerAccountItem: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, MetaChainAccountResponse), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaChainAccountResponse { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaChainAccountResponse)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: controllerAccountItem) { $0.1 }] + return cuckoo_manager.verify("showConfirmation(from: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showAdvancedSettings(from view: M1, secretSource: M2, settings: M3) -> Cuckoo.__DoNotUse<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings), Void> where M1.OptionalMatchedType == ExportGenericViewProtocol, M2.MatchedType == SecretSource, M3.MatchedType == AdvancedWalletSettings { - let matchers: [Cuckoo.ParameterMatcher<(ExportGenericViewProtocol?, SecretSource, AdvancedWalletSettings)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: secretSource) { $0.1 }, wrap(matchable: settings) { $0.2 }] - return cuckoo_manager.verify("showAdvancedSettings(from: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func close(view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(view: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentAccountSelection(_ accounts: M1, selectedAccountItem: M2, title: M3, delegate: M4, from view: M5, context: M6) -> Cuckoo.__DoNotUse<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?), Void> where M1.MatchedType == [MetaChainAccountResponse], M2.OptionalMatchedType == MetaChainAccountResponse, M3.MatchedType == LocalizableResource, M4.MatchedType == ModalPickerViewControllerDelegate, M5.OptionalMatchedType == ControllerBackedProtocol, M6.OptionalMatchedType == AnyObject { + let matchers: [Cuckoo.ParameterMatcher<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)>] = [wrap(matchable: accounts) { $0.0 }, wrap(matchable: selectedAccountItem) { $0.1 }, wrap(matchable: title) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: view) { $0.4 }, wrap(matchable: context) { $0.5 }] + return cuckoo_manager.verify("presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -22154,16 +21218,10 @@ import Foundation return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - @discardableResult - func share(source: M1, from view: M2, with completionHandler: M3) -> Cuckoo.__DoNotUse<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?), Void> where M1.MatchedType == UIActivityItemSource, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == SharingCompletionHandler { - let matchers: [Cuckoo.ParameterMatcher<(UIActivityItemSource, ControllerBackedProtocol?, SharingCompletionHandler?)>] = [wrap(matchable: source) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: completionHandler) { $0.2 }] - return cuckoo_manager.verify("share(source: UIActivityItemSource, from: ControllerBackedProtocol?, with: SharingCompletionHandler?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } - class ExportRestoreJsonWireframeProtocolStub: ExportRestoreJsonWireframeProtocol { + class ControllerAccountWireframeProtocolStub: ControllerAccountWireframeProtocol { @@ -22171,31 +21229,37 @@ import Foundation - func close(view: ExportGenericViewProtocol?) { + func showConfirmation(from view: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showAdvancedSettings(from view: ExportGenericViewProtocol?, secretSource: SecretSource, settings: AdvancedWalletSettings) { + func close(view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func presentAccountSelection(_ accounts: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from view: ControllerBackedProtocol?, context: AnyObject?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func share(source: UIActivityItemSource, from view: ControllerBackedProtocol?, with completionHandler: SharingCompletionHandler?) { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -22205,62 +21269,51 @@ import Foundation import Cuckoo @testable import novawallet +import BigInt import Foundation +import RobinHood - class MockOnboardingMainViewProtocol: OnboardingMainViewProtocol, Cuckoo.ProtocolMock { + class MockNetworkStakingInfoOperationFactoryProtocol: NetworkStakingInfoOperationFactoryProtocol, Cuckoo.ProtocolMock { - typealias MocksType = OnboardingMainViewProtocol + typealias MocksType = NetworkStakingInfoOperationFactoryProtocol - typealias Stubbing = __StubbingProxy_OnboardingMainViewProtocol - typealias Verification = __VerificationProxy_OnboardingMainViewProtocol + typealias Stubbing = __StubbingProxy_NetworkStakingInfoOperationFactoryProtocol + typealias Verification = __VerificationProxy_NetworkStakingInfoOperationFactoryProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: OnboardingMainViewProtocol? + private var __defaultImplStub: NetworkStakingInfoOperationFactoryProtocol? - func enableDefaultImplementation(_ stub: OnboardingMainViewProtocol) { + func enableDefaultImplementation(_ stub: NetworkStakingInfoOperationFactoryProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } + - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } + func networkStakingOperation(for eraValidatorService: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper { + + return cuckoo_manager.call("networkStakingOperation(for: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper", + parameters: (eraValidatorService, runtimeService), + escapingParameters: (eraValidatorService, runtimeService), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.networkStakingOperation(for: eraValidatorService, runtimeService: runtimeService)) } - - - - - struct __StubbingProxy_OnboardingMainViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_NetworkStakingInfoOperationFactoryProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -22268,19 +21321,14 @@ import Foundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") + func networkStakingOperation(for eraValidatorService: M1, runtimeService: M2) -> Cuckoo.ProtocolStubFunction<(EraValidatorServiceProtocol, RuntimeCodingServiceProtocol), CompoundOperationWrapper> where M1.MatchedType == EraValidatorServiceProtocol, M2.MatchedType == RuntimeCodingServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(EraValidatorServiceProtocol, RuntimeCodingServiceProtocol)>] = [wrap(matchable: eraValidatorService) { $0.0 }, wrap(matchable: runtimeService) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockNetworkStakingInfoOperationFactoryProtocol.self, method: "networkStakingOperation(for: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper", parameterMatchers: matchers)) } - } - struct __VerificationProxy_OnboardingMainViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_NetworkStakingInfoOperationFactoryProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -22292,62 +21340,52 @@ import Foundation } + - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func networkStakingOperation(for eraValidatorService: M1, runtimeService: M2) -> Cuckoo.__DoNotUse<(EraValidatorServiceProtocol, RuntimeCodingServiceProtocol), CompoundOperationWrapper> where M1.MatchedType == EraValidatorServiceProtocol, M2.MatchedType == RuntimeCodingServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(EraValidatorServiceProtocol, RuntimeCodingServiceProtocol)>] = [wrap(matchable: eraValidatorService) { $0.0 }, wrap(matchable: runtimeService) { $0.1 }] + return cuckoo_manager.verify("networkStakingOperation(for: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - } } - class OnboardingMainViewProtocolStub: OnboardingMainViewProtocol { - + class NetworkStakingInfoOperationFactoryProtocolStub: NetworkStakingInfoOperationFactoryProtocol { + - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - + - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - + + func networkStakingOperation(for eraValidatorService: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper { + return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper).self) } +} - - -} +import Cuckoo +@testable import novawallet +import Foundation +import RobinHood - class MockOnboardingMainPresenterProtocol: OnboardingMainPresenterProtocol, Cuckoo.ProtocolMock { + class MockValidatorOperationFactoryProtocol: ValidatorOperationFactoryProtocol, Cuckoo.ProtocolMock { - typealias MocksType = OnboardingMainPresenterProtocol + typealias MocksType = ValidatorOperationFactoryProtocol - typealias Stubbing = __StubbingProxy_OnboardingMainPresenterProtocol - typealias Verification = __VerificationProxy_OnboardingMainPresenterProtocol + typealias Stubbing = __StubbingProxy_ValidatorOperationFactoryProtocol + typealias Verification = __VerificationProxy_ValidatorOperationFactoryProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: OnboardingMainPresenterProtocol? + private var __defaultImplStub: ValidatorOperationFactoryProtocol? - func enableDefaultImplementation(_ stub: OnboardingMainPresenterProtocol) { + func enableDefaultImplementation(_ stub: ValidatorOperationFactoryProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -22360,111 +21398,81 @@ import Foundation - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - - } - - - - func activateSignup() { - - return cuckoo_manager.call("activateSignup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.activateSignup()) - - } - - - - func activateAccountRestore() { + func allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]> { - return cuckoo_manager.call("activateAccountRestore()", + return cuckoo_manager.call("allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]>", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activateAccountRestore()) + defaultCall: __defaultImplStub!.allElectedOperation()) } - func activateWatchOnlyCreate() { + func allSelectedOperation(by nomination: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { - return cuckoo_manager.call("activateWatchOnlyCreate()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("allSelectedOperation(by: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", + parameters: (nomination, nominatorAddress), + escapingParameters: (nomination, nominatorAddress), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activateWatchOnlyCreate()) + defaultCall: __defaultImplStub!.allSelectedOperation(by: nomination, nominatorAddress: nominatorAddress)) } - func activateHardwareWalletCreate() { + func activeValidatorsOperation(for nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { - return cuckoo_manager.call("activateHardwareWalletCreate()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("activeValidatorsOperation(for: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", + parameters: (nominatorAddress), + escapingParameters: (nominatorAddress), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activateHardwareWalletCreate()) + defaultCall: __defaultImplStub!.activeValidatorsOperation(for: nominatorAddress)) } - func activateTerms() { + func pendingValidatorsOperation(for accountIds: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { - return cuckoo_manager.call("activateTerms()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("pendingValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", + parameters: (accountIds), + escapingParameters: (accountIds), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activateTerms()) + defaultCall: __defaultImplStub!.pendingValidatorsOperation(for: accountIds)) } - func activatePrivacy() { + func wannabeValidatorsOperation(for accountIdList: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { - return cuckoo_manager.call("activatePrivacy()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("wannabeValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", + parameters: (accountIdList), + escapingParameters: (accountIdList), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activatePrivacy()) + defaultCall: __defaultImplStub!.wannabeValidatorsOperation(for: accountIdList)) } - struct __StubbingProxy_OnboardingMainPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorOperationFactoryProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -22472,44 +21480,34 @@ import Foundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func activateSignup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateSignup()", parameterMatchers: matchers)) - } - - func activateAccountRestore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func allElectedOperation() -> Cuckoo.ProtocolStubFunction<(), CompoundOperationWrapper<[ElectedValidatorInfo]>> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateAccountRestore()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]>", parameterMatchers: matchers)) } - func activateWatchOnlyCreate() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateWatchOnlyCreate()", parameterMatchers: matchers)) + func allSelectedOperation(by nomination: M1, nominatorAddress: M2) -> Cuckoo.ProtocolStubFunction<(Nomination, AccountAddress), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == Nomination, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(Nomination, AccountAddress)>] = [wrap(matchable: nomination) { $0.0 }, wrap(matchable: nominatorAddress) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "allSelectedOperation(by: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", parameterMatchers: matchers)) } - func activateHardwareWalletCreate() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateHardwareWalletCreate()", parameterMatchers: matchers)) + func activeValidatorsOperation(for nominatorAddress: M1) -> Cuckoo.ProtocolStubFunction<(AccountAddress), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: nominatorAddress) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "activeValidatorsOperation(for: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", parameterMatchers: matchers)) } - func activateTerms() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activateTerms()", parameterMatchers: matchers)) + func pendingValidatorsOperation(for accountIds: M1) -> Cuckoo.ProtocolStubFunction<([AccountId]), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == [AccountId] { + let matchers: [Cuckoo.ParameterMatcher<([AccountId])>] = [wrap(matchable: accountIds) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "pendingValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", parameterMatchers: matchers)) } - func activatePrivacy() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainPresenterProtocol.self, method: "activatePrivacy()", parameterMatchers: matchers)) + func wannabeValidatorsOperation(for accountIdList: M1) -> Cuckoo.ProtocolStubFunction<([AccountId]), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == [AccountId] { + let matchers: [Cuckoo.ParameterMatcher<([AccountId])>] = [wrap(matchable: accountIdList) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "wannabeValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", parameterMatchers: matchers)) } } - struct __VerificationProxy_OnboardingMainPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorOperationFactoryProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -22524,51 +21522,39 @@ import Foundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func activateSignup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateSignup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func activateAccountRestore() -> Cuckoo.__DoNotUse<(), Void> { + func allElectedOperation() -> Cuckoo.__DoNotUse<(), CompoundOperationWrapper<[ElectedValidatorInfo]>> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateAccountRestore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func activateWatchOnlyCreate() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateWatchOnlyCreate()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func allSelectedOperation(by nomination: M1, nominatorAddress: M2) -> Cuckoo.__DoNotUse<(Nomination, AccountAddress), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == Nomination, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(Nomination, AccountAddress)>] = [wrap(matchable: nomination) { $0.0 }, wrap(matchable: nominatorAddress) { $0.1 }] + return cuckoo_manager.verify("allSelectedOperation(by: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func activateHardwareWalletCreate() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateHardwareWalletCreate()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func activeValidatorsOperation(for nominatorAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: nominatorAddress) { $0 }] + return cuckoo_manager.verify("activeValidatorsOperation(for: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func activateTerms() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateTerms()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func pendingValidatorsOperation(for accountIds: M1) -> Cuckoo.__DoNotUse<([AccountId]), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == [AccountId] { + let matchers: [Cuckoo.ParameterMatcher<([AccountId])>] = [wrap(matchable: accountIds) { $0 }] + return cuckoo_manager.verify("pendingValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func activatePrivacy() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activatePrivacy()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func wannabeValidatorsOperation(for accountIdList: M1) -> Cuckoo.__DoNotUse<([AccountId]), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == [AccountId] { + let matchers: [Cuckoo.ParameterMatcher<([AccountId])>] = [wrap(matchable: accountIdList) { $0 }] + return cuckoo_manager.verify("wannabeValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class OnboardingMainPresenterProtocolStub: OnboardingMainPresenterProtocol { + class ValidatorOperationFactoryProtocolStub: ValidatorOperationFactoryProtocol { @@ -22576,210 +21562,165 @@ import Foundation - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func activateSignup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func activateAccountRestore() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]> { + return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[ElectedValidatorInfo]>).self) } - func activateWatchOnlyCreate() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func allSelectedOperation(by nomination: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { + return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[SelectedValidatorInfo]>).self) } - func activateHardwareWalletCreate() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func activeValidatorsOperation(for nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { + return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[SelectedValidatorInfo]>).self) } - func activateTerms() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func pendingValidatorsOperation(for accountIds: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { + return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[SelectedValidatorInfo]>).self) } - func activatePrivacy() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func wannabeValidatorsOperation(for accountIdList: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { + return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[SelectedValidatorInfo]>).self) } } +import Cuckoo +@testable import novawallet - class MockOnboardingMainWireframeProtocol: OnboardingMainWireframeProtocol, Cuckoo.ProtocolMock { +import SoraFoundation + + + class MockCustomValidatorListViewProtocol: CustomValidatorListViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = OnboardingMainWireframeProtocol + typealias MocksType = CustomValidatorListViewProtocol - typealias Stubbing = __StubbingProxy_OnboardingMainWireframeProtocol - typealias Verification = __VerificationProxy_OnboardingMainWireframeProtocol + typealias Stubbing = __StubbingProxy_CustomValidatorListViewProtocol + typealias Verification = __VerificationProxy_CustomValidatorListViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: OnboardingMainWireframeProtocol? + private var __defaultImplStub: CustomValidatorListViewProtocol? - func enableDefaultImplementation(_ stub: OnboardingMainWireframeProtocol) { + func enableDefaultImplementation(_ stub: CustomValidatorListViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - - - func showSignup(from view: OnboardingMainViewProtocol?) { - - return cuckoo_manager.call("showSignup(from: OnboardingMainViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showSignup(from: view)) + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } } - func showAccountRestore(from view: OnboardingMainViewProtocol?) { - - return cuckoo_manager.call("showAccountRestore(from: OnboardingMainViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showAccountRestore(from: view)) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } - func showKeystoreImport(from view: OnboardingMainViewProtocol?) { - - return cuckoo_manager.call("showKeystoreImport(from: OnboardingMainViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showKeystoreImport(from: view)) - - } - - - - func showWatchOnlyCreate(from view: OnboardingMainViewProtocol?) { - - return cuckoo_manager.call("showWatchOnlyCreate(from: OnboardingMainViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showWatchOnlyCreate(from: view)) - - } - - - - func showParitySignerWalletCreation(from view: OnboardingMainViewProtocol?) { + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } - return cuckoo_manager.call("showParitySignerWalletCreation(from: OnboardingMainViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showParitySignerWalletCreation(from: view)) + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } } + - - func showLedgerWalletCreation(from view: OnboardingMainViewProtocol?) { - - return cuckoo_manager.call("showLedgerWalletCreation(from: OnboardingMainViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showLedgerWalletCreation(from: view)) - - } + - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func reload(_ viewModel: CustomValidatorListViewModel, at indexes: [Int]?) { - return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", - parameters: (url, view, style), - escapingParameters: (url, view, style), + return cuckoo_manager.call("reload(_: CustomValidatorListViewModel, at: [Int]?)", + parameters: (viewModel, indexes), + escapingParameters: (viewModel, indexes), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) + defaultCall: __defaultImplStub!.reload(viewModel, at: indexes)) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func setFilterAppliedState(to state: Bool) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("setFilterAppliedState(to: Bool)", + parameters: (state), + escapingParameters: (state), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.setFilterAppliedState(to: state)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + public func applyLocalization() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_OnboardingMainWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CustomValidatorListViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -22787,54 +21728,39 @@ import Foundation } - func showSignup(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showSignup(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func showAccountRestore(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showAccountRestore(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) - } - func showKeystoreImport(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showKeystoreImport(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func showWatchOnlyCreate(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showWatchOnlyCreate(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) - } - func showParitySignerWalletCreation(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showParitySignerWalletCreation(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func showLedgerWalletCreation(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OnboardingMainViewProtocol?)> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showLedgerWalletCreation(from: OnboardingMainViewProtocol?)", parameterMatchers: matchers)) - } - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) + func reload(_ viewModel: M1, at indexes: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(CustomValidatorListViewModel, [Int]?)> where M1.MatchedType == CustomValidatorListViewModel, M2.OptionalMatchedType == [Int] { + let matchers: [Cuckoo.ParameterMatcher<(CustomValidatorListViewModel, [Int]?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: indexes) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListViewProtocol.self, method: "reload(_: CustomValidatorListViewModel, at: [Int]?)", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func setFilterAppliedState(to state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: state) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListViewProtocol.self, method: "setFilterAppliedState(to: Bool)", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_OnboardingMainWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CustomValidatorListViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -22846,122 +21772,94 @@ import Foundation } - - @discardableResult - func showSignup(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showSignup(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func showAccountRestore(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showAccountRestore(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - @discardableResult - func showKeystoreImport(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showKeystoreImport(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func showWatchOnlyCreate(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showWatchOnlyCreate(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - @discardableResult - func showParitySignerWalletCreation(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showParitySignerWalletCreation(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func showLedgerWalletCreation(from view: M1) -> Cuckoo.__DoNotUse<(OnboardingMainViewProtocol?), Void> where M1.OptionalMatchedType == OnboardingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(OnboardingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showLedgerWalletCreation(from: OnboardingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } + @discardableResult - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload(_ viewModel: M1, at indexes: M2) -> Cuckoo.__DoNotUse<(CustomValidatorListViewModel, [Int]?), Void> where M1.MatchedType == CustomValidatorListViewModel, M2.OptionalMatchedType == [Int] { + let matchers: [Cuckoo.ParameterMatcher<(CustomValidatorListViewModel, [Int]?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: indexes) { $0.1 }] + return cuckoo_manager.verify("reload(_: CustomValidatorListViewModel, at: [Int]?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setFilterAppliedState(to state: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: state) { $0 }] + return cuckoo_manager.verify("setFilterAppliedState(to: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class OnboardingMainWireframeProtocolStub: OnboardingMainWireframeProtocol { - - - - - - - - func showSignup(from view: OnboardingMainViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showAccountRestore(from view: OnboardingMainViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - + class CustomValidatorListViewProtocolStub: CustomValidatorListViewProtocol { + - func showKeystoreImport(from view: OnboardingMainViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + } + - - func showWatchOnlyCreate(from view: OnboardingMainViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + - - func showParitySignerWalletCreation(from view: OnboardingMainViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + } + - - func showLedgerWalletCreation(from view: OnboardingMainViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func reload(_ viewModel: CustomValidatorListViewModel, at indexes: [Int]?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func setFilterAppliedState(to state: Bool) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -22969,19 +21867,19 @@ import Foundation - class MockOnboardingMainInteractorInputProtocol: OnboardingMainInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockCustomValidatorListPresenterProtocol: CustomValidatorListPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = OnboardingMainInteractorInputProtocol + typealias MocksType = CustomValidatorListPresenterProtocol - typealias Stubbing = __StubbingProxy_OnboardingMainInteractorInputProtocol - typealias Verification = __VerificationProxy_OnboardingMainInteractorInputProtocol + typealias Stubbing = __StubbingProxy_CustomValidatorListPresenterProtocol + typealias Verification = __VerificationProxy_CustomValidatorListPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: OnboardingMainInteractorInputProtocol? + private var __defaultImplStub: CustomValidatorListPresenterProtocol? - func enableDefaultImplementation(_ stub: OnboardingMainInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: CustomValidatorListPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -23007,101 +21905,143 @@ import Foundation } - - struct __StubbingProxy_OnboardingMainInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_OnboardingMainInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class OnboardingMainInteractorInputProtocolStub: OnboardingMainInteractorInputProtocol { - - + func fillWithRecommended() { + + return cuckoo_manager.call("fillWithRecommended()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.fillWithRecommended()) + + } - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func clearFilter() { + + return cuckoo_manager.call("clearFilter()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.clearFilter()) + } -} - - - - class MockOnboardingMainInteractorOutputProtocol: OnboardingMainInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = OnboardingMainInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_OnboardingMainInteractorOutputProtocol - typealias Verification = __VerificationProxy_OnboardingMainInteractorOutputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - + func deselectAll() { + + return cuckoo_manager.call("deselectAll()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.deselectAll()) + + } - private var __defaultImplStub: OnboardingMainInteractorOutputProtocol? - - func enableDefaultImplementation(_ stub: OnboardingMainInteractorOutputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + + + func changeValidatorSelection(at index: Int) { + + return cuckoo_manager.call("changeValidatorSelection(at: Int)", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.changeValidatorSelection(at: index)) + } - - - + func didSelectValidator(at index: Int) { + + return cuckoo_manager.call("didSelectValidator(at: Int)", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didSelectValidator(at: index)) + + } - func didSuggestKeystoreImport() { + func presentFilter() { - return cuckoo_manager.call("didSuggestKeystoreImport()", + return cuckoo_manager.call("presentFilter()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didSuggestKeystoreImport()) + defaultCall: __defaultImplStub!.presentFilter()) + + } + + + + func presentSearch() { + + return cuckoo_manager.call("presentSearch()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentSearch()) + + } + + + + func proceed() { + + return cuckoo_manager.call("proceed()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.proceed()) + + } + + + + func didRemove(_ validator: SelectedValidatorInfo) { + + return cuckoo_manager.call("didRemove(_: SelectedValidatorInfo)", + parameters: (validator), + escapingParameters: (validator), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didRemove(validator)) } - struct __StubbingProxy_OnboardingMainInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CustomValidatorListPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -23109,14 +22049,59 @@ import Foundation } - func didSuggestKeystoreImport() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOnboardingMainInteractorOutputProtocol.self, method: "didSuggestKeystoreImport()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func fillWithRecommended() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "fillWithRecommended()", parameterMatchers: matchers)) + } + + func clearFilter() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "clearFilter()", parameterMatchers: matchers)) + } + + func deselectAll() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "deselectAll()", parameterMatchers: matchers)) + } + + func changeValidatorSelection(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "changeValidatorSelection(at: Int)", parameterMatchers: matchers)) + } + + func didSelectValidator(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "didSelectValidator(at: Int)", parameterMatchers: matchers)) + } + + func presentFilter() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "presentFilter()", parameterMatchers: matchers)) + } + + func presentSearch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "presentSearch()", parameterMatchers: matchers)) + } + + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + } + + func didRemove(_ validator: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorInfo)> where M1.MatchedType == SelectedValidatorInfo { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo)>] = [wrap(matchable: validator) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "didRemove(_: SelectedValidatorInfo)", parameterMatchers: matchers)) } } - struct __VerificationProxy_OnboardingMainInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CustomValidatorListPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -23131,294 +22116,178 @@ import Foundation @discardableResult - func didSuggestKeystoreImport() -> Cuckoo.__DoNotUse<(), Void> { + func setup() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didSuggestKeystoreImport()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - } -} - - class OnboardingMainInteractorOutputProtocolStub: OnboardingMainInteractorOutputProtocol { - - - - - - - - func didSuggestKeystoreImport() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - -import Cuckoo -@testable import novawallet - -import CommonWallet - - - class MockOperationDetailsViewProtocol: OperationDetailsViewProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = OperationDetailsViewProtocol - - typealias Stubbing = __StubbingProxy_OperationDetailsViewProtocol - typealias Verification = __VerificationProxy_OperationDetailsViewProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: OperationDetailsViewProtocol? - - func enableDefaultImplementation(_ stub: OperationDetailsViewProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - - - - - - - func didReceive(viewModel: OperationDetailsViewModel) { - - return cuckoo_manager.call("didReceive(viewModel: OperationDetailsViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) - - } - - - struct __StubbingProxy_OperationDetailsViewProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager + @discardableResult + func fillWithRecommended() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("fillWithRecommended()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") + @discardableResult + func clearFilter() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("clearFilter()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") + @discardableResult + func deselectAll() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("deselectAll()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(OperationDetailsViewModel)> where M1.MatchedType == OperationDetailsViewModel { - let matchers: [Cuckoo.ParameterMatcher<(OperationDetailsViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsViewProtocol.self, method: "didReceive(viewModel: OperationDetailsViewModel)", parameterMatchers: matchers)) + @discardableResult + func changeValidatorSelection(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("changeValidatorSelection(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - } - - struct __VerificationProxy_OperationDetailsViewProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation + @discardableResult + func didSelectValidator(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("didSelectValidator(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func presentFilter() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentFilter()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func presentSearch() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentSearch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - + @discardableResult + func proceed() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } @discardableResult - func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(OperationDetailsViewModel), Void> where M1.MatchedType == OperationDetailsViewModel { - let matchers: [Cuckoo.ParameterMatcher<(OperationDetailsViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceive(viewModel: OperationDetailsViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didRemove(_ validator: M1) -> Cuckoo.__DoNotUse<(SelectedValidatorInfo), Void> where M1.MatchedType == SelectedValidatorInfo { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo)>] = [wrap(matchable: validator) { $0 }] + return cuckoo_manager.verify("didRemove(_: SelectedValidatorInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class OperationDetailsViewProtocolStub: OperationDetailsViewProtocol { - + class CustomValidatorListPresenterProtocolStub: CustomValidatorListPresenterProtocol { + - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + + + + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - + + func fillWithRecommended() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - + + func clearFilter() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func didReceive(viewModel: OperationDetailsViewModel) { + func deselectAll() { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockOperationDetailsPresenterProtocol: OperationDetailsPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = OperationDetailsPresenterProtocol - typealias Stubbing = __StubbingProxy_OperationDetailsPresenterProtocol - typealias Verification = __VerificationProxy_OperationDetailsPresenterProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - + func changeValidatorSelection(at index: Int) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - private var __defaultImplStub: OperationDetailsPresenterProtocol? - - func enableDefaultImplementation(_ stub: OperationDetailsPresenterProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + + + func didSelectValidator(at index: Int) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - + func presentFilter() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - + func presentSearch() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showSenderActions() { - - return cuckoo_manager.call("showSenderActions()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showSenderActions()) - + func proceed() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showRecepientActions() { - - return cuckoo_manager.call("showRecepientActions()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showRecepientActions()) - + func didRemove(_ validator: SelectedValidatorInfo) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockCustomValidatorListViewModelFactoryProtocol: CustomValidatorListViewModelFactoryProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = CustomValidatorListViewModelFactoryProtocol + typealias Stubbing = __StubbingProxy_CustomValidatorListViewModelFactoryProtocol + typealias Verification = __VerificationProxy_CustomValidatorListViewModelFactoryProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func showOperationActions() { - - return cuckoo_manager.call("showOperationActions()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showOperationActions()) - + private var __defaultImplStub: CustomValidatorListViewModelFactoryProtocol? + + func enableDefaultImplementation(_ stub: CustomValidatorListViewModelFactoryProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func send() { + + + + + func createViewModel(from validatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel { - return cuckoo_manager.call("send()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel", + parameters: (validatorList, selectedValidatorList, totalValidatorsCount, filter, priceData, locale), + escapingParameters: (validatorList, selectedValidatorList, totalValidatorsCount, filter, priceData, locale), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.send()) + defaultCall: __defaultImplStub!.createViewModel(from: validatorList, selectedValidatorList: selectedValidatorList, totalValidatorsCount: totalValidatorsCount, filter: filter, priceData: priceData, locale: locale)) } - struct __StubbingProxy_OperationDetailsPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CustomValidatorListViewModelFactoryProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -23426,34 +22295,14 @@ import CommonWallet } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func showSenderActions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "showSenderActions()", parameterMatchers: matchers)) - } - - func showRecepientActions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "showRecepientActions()", parameterMatchers: matchers)) - } - - func showOperationActions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "showOperationActions()", parameterMatchers: matchers)) - } - - func send() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsPresenterProtocol.self, method: "send()", parameterMatchers: matchers)) + func createViewModel(from validatorList: M1, selectedValidatorList: M2, totalValidatorsCount: M3, filter: M4, priceData: M5, locale: M6) -> Cuckoo.ProtocolStubFunction<([SelectedValidatorInfo], [SelectedValidatorInfo], Int, CustomValidatorListFilter, PriceData?, Locale), CustomValidatorListViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int, M4.MatchedType == CustomValidatorListFilter, M5.OptionalMatchedType == PriceData, M6.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], [SelectedValidatorInfo], Int, CustomValidatorListFilter, PriceData?, Locale)>] = [wrap(matchable: validatorList) { $0.0 }, wrap(matchable: selectedValidatorList) { $0.1 }, wrap(matchable: totalValidatorsCount) { $0.2 }, wrap(matchable: filter) { $0.3 }, wrap(matchable: priceData) { $0.4 }, wrap(matchable: locale) { $0.5 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListViewModelFactoryProtocol.self, method: "createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel", parameterMatchers: matchers)) } } - struct __VerificationProxy_OperationDetailsPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CustomValidatorListViewModelFactoryProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -23468,39 +22317,15 @@ import CommonWallet @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showSenderActions() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("showSenderActions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showRecepientActions() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("showRecepientActions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showOperationActions() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("showOperationActions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func send() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("send()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func createViewModel(from validatorList: M1, selectedValidatorList: M2, totalValidatorsCount: M3, filter: M4, priceData: M5, locale: M6) -> Cuckoo.__DoNotUse<([SelectedValidatorInfo], [SelectedValidatorInfo], Int, CustomValidatorListFilter, PriceData?, Locale), CustomValidatorListViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int, M4.MatchedType == CustomValidatorListFilter, M5.OptionalMatchedType == PriceData, M6.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], [SelectedValidatorInfo], Int, CustomValidatorListFilter, PriceData?, Locale)>] = [wrap(matchable: validatorList) { $0.0 }, wrap(matchable: selectedValidatorList) { $0.1 }, wrap(matchable: totalValidatorsCount) { $0.2 }, wrap(matchable: filter) { $0.3 }, wrap(matchable: priceData) { $0.4 }, wrap(matchable: locale) { $0.5 }] + return cuckoo_manager.verify("createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class OperationDetailsPresenterProtocolStub: OperationDetailsPresenterProtocol { + class CustomValidatorListViewModelFactoryProtocolStub: CustomValidatorListViewModelFactoryProtocol { @@ -23508,51 +22333,27 @@ import CommonWallet - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showSenderActions() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showRecepientActions() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showOperationActions() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func send() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func createViewModel(from validatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel { + return DefaultValueRegistry.defaultValue(for: (CustomValidatorListViewModel).self) } } - class MockOperationDetailsInteractorInputProtocol: OperationDetailsInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockCustomValidatorListInteractorInputProtocol: CustomValidatorListInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = OperationDetailsInteractorInputProtocol + typealias MocksType = CustomValidatorListInteractorInputProtocol - typealias Stubbing = __StubbingProxy_OperationDetailsInteractorInputProtocol - typealias Verification = __VerificationProxy_OperationDetailsInteractorInputProtocol + typealias Stubbing = __StubbingProxy_CustomValidatorListInteractorInputProtocol + typealias Verification = __VerificationProxy_CustomValidatorListInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: OperationDetailsInteractorInputProtocol? + private var __defaultImplStub: CustomValidatorListInteractorInputProtocol? - func enableDefaultImplementation(_ stub: OperationDetailsInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: CustomValidatorListInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -23579,7 +22380,7 @@ import CommonWallet } - struct __StubbingProxy_OperationDetailsInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CustomValidatorListInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -23589,12 +22390,12 @@ import CommonWallet func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } } - struct __VerificationProxy_OperationDetailsInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CustomValidatorListInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -23617,7 +22418,7 @@ import CommonWallet } } - class OperationDetailsInteractorInputProtocolStub: OperationDetailsInteractorInputProtocol { + class CustomValidatorListInteractorInputProtocolStub: CustomValidatorListInteractorInputProtocol { @@ -23633,19 +22434,19 @@ import CommonWallet - class MockOperationDetailsInteractorOutputProtocol: OperationDetailsInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockCustomValidatorListInteractorOutputProtocol: CustomValidatorListInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = OperationDetailsInteractorOutputProtocol + typealias MocksType = CustomValidatorListInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_OperationDetailsInteractorOutputProtocol - typealias Verification = __VerificationProxy_OperationDetailsInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_CustomValidatorListInteractorOutputProtocol + typealias Verification = __VerificationProxy_CustomValidatorListInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: OperationDetailsInteractorOutputProtocol? + private var __defaultImplStub: CustomValidatorListInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: OperationDetailsInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: CustomValidatorListInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -23658,21 +22459,21 @@ import CommonWallet - func didReceiveDetails(result: Result) { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("didReceiveDetails(result: Result)", + return cuckoo_manager.call("didReceivePriceData(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveDetails(result: result)) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - struct __StubbingProxy_OperationDetailsInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CustomValidatorListInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -23680,14 +22481,14 @@ import CommonWallet } - func didReceiveDetails(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsInteractorOutputProtocol.self, method: "didReceiveDetails(result: Result)", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_OperationDetailsInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CustomValidatorListInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -23702,15 +22503,15 @@ import CommonWallet @discardableResult - func didReceiveDetails(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveDetails(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class OperationDetailsInteractorOutputProtocolStub: OperationDetailsInteractorOutputProtocol { + class CustomValidatorListInteractorOutputProtocolStub: CustomValidatorListInteractorOutputProtocol { @@ -23718,7 +22519,7 @@ import CommonWallet - func didReceiveDetails(result: Result) { + func didReceivePriceData(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -23726,19 +22527,19 @@ import CommonWallet - class MockOperationDetailsWireframeProtocol: OperationDetailsWireframeProtocol, Cuckoo.ProtocolMock { + class MockCustomValidatorListWireframeProtocol: CustomValidatorListWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = OperationDetailsWireframeProtocol + typealias MocksType = CustomValidatorListWireframeProtocol - typealias Stubbing = __StubbingProxy_OperationDetailsWireframeProtocol - typealias Verification = __VerificationProxy_OperationDetailsWireframeProtocol + typealias Stubbing = __StubbingProxy_CustomValidatorListWireframeProtocol + typealias Verification = __VerificationProxy_CustomValidatorListWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: OperationDetailsWireframeProtocol? + private var __defaultImplStub: CustomValidatorListWireframeProtocol? - func enableDefaultImplementation(_ stub: OperationDetailsWireframeProtocol) { + func enableDefaultImplementation(_ stub: CustomValidatorListWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -23751,16 +22552,61 @@ import CommonWallet - func showSend(from view: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset) { + func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("showSend(from: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset)", - parameters: (view, displayAddress, chainAsset), - escapingParameters: (view, displayAddress, chainAsset), + return cuckoo_manager.call("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", + parameters: (validatorInfo, view), + escapingParameters: (validatorInfo, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showSend(from: view, displayAddress: displayAddress, chainAsset: chainAsset)) + defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) + + } + + + + func presentFilters(from view: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?) { + + return cuckoo_manager.call("presentFilters(from: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?)", + parameters: (view, filter, hasIdentity, delegate), + escapingParameters: (view, filter, hasIdentity, delegate), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentFilters(from: view, filter: filter, hasIdentity: hasIdentity, delegate: delegate)) + + } + + + + func presentSearch(from view: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?) { + + return cuckoo_manager.call("presentSearch(from: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?)", + parameters: (view, fullValidatorList, selectedValidatorList, delegate), + escapingParameters: (view, fullValidatorList, selectedValidatorList, delegate), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentSearch(from: view, fullValidatorList: fullValidatorList, selectedValidatorList: selectedValidatorList, delegate: delegate)) + + } + + + + func proceed(from view: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate) { + + return cuckoo_manager.call("proceed(from: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate)", + parameters: (view, validatorList, maxTargets, delegate), + escapingParameters: (view, validatorList, maxTargets, delegate), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.proceed(from: view, validatorList: validatorList, maxTargets: maxTargets, delegate: delegate)) } @@ -23795,7 +22641,7 @@ import CommonWallet } - struct __StubbingProxy_OperationDetailsWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CustomValidatorListWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -23803,24 +22649,39 @@ import CommonWallet } - func showSend(from view: M1, displayAddress: M2, chainAsset: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(OperationDetailsViewProtocol?, DisplayAddress, ChainAsset)> where M1.OptionalMatchedType == OperationDetailsViewProtocol, M2.MatchedType == DisplayAddress, M3.MatchedType == ChainAsset { - let matchers: [Cuckoo.ParameterMatcher<(OperationDetailsViewProtocol?, DisplayAddress, ChainAsset)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: displayAddress) { $0.1 }, wrap(matchable: chainAsset) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsWireframeProtocol.self, method: "showSend(from: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset)", parameterMatchers: matchers)) + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoProtocol, ControllerBackedProtocol?)> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func presentFilters(from view: M1, filter: M2, hasIdentity: M3, delegate: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, CustomValidatorListFilter, Bool, ValidatorListFilterDelegate?)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == CustomValidatorListFilter, M3.MatchedType == Bool, M4.OptionalMatchedType == ValidatorListFilterDelegate { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, CustomValidatorListFilter, Bool, ValidatorListFilterDelegate?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: filter) { $0.1 }, wrap(matchable: hasIdentity) { $0.2 }, wrap(matchable: delegate) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "presentFilters(from: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?)", parameterMatchers: matchers)) + } + + func presentSearch(from view: M1, fullValidatorList: M2, selectedValidatorList: M3, delegate: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, [SelectedValidatorInfo], [SelectedValidatorInfo], ValidatorSearchDelegate?)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == [SelectedValidatorInfo], M4.OptionalMatchedType == ValidatorSearchDelegate { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, [SelectedValidatorInfo], [SelectedValidatorInfo], ValidatorSearchDelegate?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: fullValidatorList) { $0.1 }, wrap(matchable: selectedValidatorList) { $0.2 }, wrap(matchable: delegate) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "presentSearch(from: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?)", parameterMatchers: matchers)) + } + + func proceed(from view: M1, validatorList: M2, maxTargets: M3, delegate: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, [SelectedValidatorInfo], Int, SelectedValidatorListDelegate)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int, M4.MatchedType == SelectedValidatorListDelegate { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, [SelectedValidatorInfo], Int, SelectedValidatorListDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: validatorList) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }, wrap(matchable: delegate) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "proceed(from: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockOperationDetailsWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_OperationDetailsWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CustomValidatorListWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -23835,9 +22696,27 @@ import CommonWallet @discardableResult - func showSend(from view: M1, displayAddress: M2, chainAsset: M3) -> Cuckoo.__DoNotUse<(OperationDetailsViewProtocol?, DisplayAddress, ChainAsset), Void> where M1.OptionalMatchedType == OperationDetailsViewProtocol, M2.MatchedType == DisplayAddress, M3.MatchedType == ChainAsset { - let matchers: [Cuckoo.ParameterMatcher<(OperationDetailsViewProtocol?, DisplayAddress, ChainAsset)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: displayAddress) { $0.1 }, wrap(matchable: chainAsset) { $0.2 }] - return cuckoo_manager.verify("showSend(from: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(ValidatorInfoProtocol, ControllerBackedProtocol?), Void> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentFilters(from view: M1, filter: M2, hasIdentity: M3, delegate: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, CustomValidatorListFilter, Bool, ValidatorListFilterDelegate?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == CustomValidatorListFilter, M3.MatchedType == Bool, M4.OptionalMatchedType == ValidatorListFilterDelegate { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, CustomValidatorListFilter, Bool, ValidatorListFilterDelegate?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: filter) { $0.1 }, wrap(matchable: hasIdentity) { $0.2 }, wrap(matchable: delegate) { $0.3 }] + return cuckoo_manager.verify("presentFilters(from: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentSearch(from view: M1, fullValidatorList: M2, selectedValidatorList: M3, delegate: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, [SelectedValidatorInfo], [SelectedValidatorInfo], ValidatorSearchDelegate?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == [SelectedValidatorInfo], M4.OptionalMatchedType == ValidatorSearchDelegate { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, [SelectedValidatorInfo], [SelectedValidatorInfo], ValidatorSearchDelegate?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: fullValidatorList) { $0.1 }, wrap(matchable: selectedValidatorList) { $0.2 }, wrap(matchable: delegate) { $0.3 }] + return cuckoo_manager.verify("presentSearch(from: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func proceed(from view: M1, validatorList: M2, maxTargets: M3, delegate: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, [SelectedValidatorInfo], Int, SelectedValidatorListDelegate), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int, M4.MatchedType == SelectedValidatorListDelegate { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, [SelectedValidatorInfo], Int, SelectedValidatorListDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: validatorList) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }, wrap(matchable: delegate) { $0.3 }] + return cuckoo_manager.verify("proceed(from: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -23855,7 +22734,7 @@ import CommonWallet } } - class OperationDetailsWireframeProtocolStub: OperationDetailsWireframeProtocol { + class CustomValidatorListWireframeProtocolStub: CustomValidatorListWireframeProtocol { @@ -23863,7 +22742,25 @@ import CommonWallet - func showSend(from view: OperationDetailsViewProtocol?, displayAddress: DisplayAddress, chainAsset: ChainAsset) { + func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentFilters(from view: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentSearch(from view: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func proceed(from view: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -23885,22 +22782,22 @@ import CommonWallet import Cuckoo @testable import novawallet -import UIKit +import SoraFoundation - class MockPinSetupViewProtocol: PinSetupViewProtocol, Cuckoo.ProtocolMock { + class MockRecommendedValidatorListViewProtocol: RecommendedValidatorListViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = PinSetupViewProtocol + typealias MocksType = RecommendedValidatorListViewProtocol - typealias Stubbing = __StubbingProxy_PinSetupViewProtocol - typealias Verification = __VerificationProxy_PinSetupViewProtocol + typealias Stubbing = __StubbingProxy_RecommendedValidatorListViewProtocol + typealias Verification = __VerificationProxy_RecommendedValidatorListViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: PinSetupViewProtocol? + private var __defaultImplStub: RecommendedValidatorListViewProtocol? - func enableDefaultImplementation(_ stub: PinSetupViewProtocol) { + func enableDefaultImplementation(_ stub: RecommendedValidatorListViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -23935,57 +22832,66 @@ import UIKit } - - - - - func didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void) { + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } - return cuckoo_manager.call("didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", - parameters: (biometryType, completionBlock), - escapingParameters: (biometryType, completionBlock), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didRequestBiometryUsage(biometryType: biometryType, completionBlock: completionBlock)) + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } } + + + - func didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType) { + + func didReceive(viewModel: RecommendedValidatorListViewModelProtocol) { - return cuckoo_manager.call("didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType)", - parameters: (enabled, availableBiometryType), - escapingParameters: (enabled, availableBiometryType), + return cuckoo_manager.call("didReceive(viewModel: RecommendedValidatorListViewModelProtocol)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didChangeAccessoryState(enabled: enabled, availableBiometryType: availableBiometryType)) + defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) } - func didReceiveWrongPincode() { + public func applyLocalization() { - return cuckoo_manager.call("didReceiveWrongPincode()", + return cuckoo_manager.call("applyLocalization()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveWrongPincode()) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_PinSetupViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_RecommendedValidatorListViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -23993,34 +22899,34 @@ import UIKit } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - func didRequestBiometryUsage(biometryType: M1, completionBlock: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(AvailableBiometryType, (Bool) -> Void)> where M1.MatchedType == AvailableBiometryType, M2.MatchedType == (Bool) -> Void { - let matchers: [Cuckoo.ParameterMatcher<(AvailableBiometryType, (Bool) -> Void)>] = [wrap(matchable: biometryType) { $0.0 }, wrap(matchable: completionBlock) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupViewProtocol.self, method: "didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", parameterMatchers: matchers)) + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func didChangeAccessoryState(enabled: M1, availableBiometryType: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool, AvailableBiometryType)> where M1.MatchedType == Bool, M2.MatchedType == AvailableBiometryType { - let matchers: [Cuckoo.ParameterMatcher<(Bool, AvailableBiometryType)>] = [wrap(matchable: enabled) { $0.0 }, wrap(matchable: availableBiometryType) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupViewProtocol.self, method: "didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType)", parameterMatchers: matchers)) + + func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RecommendedValidatorListViewModelProtocol)> where M1.MatchedType == RecommendedValidatorListViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(RecommendedValidatorListViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListViewProtocol.self, method: "didReceive(viewModel: RecommendedValidatorListViewModelProtocol)", parameterMatchers: matchers)) } - func didReceiveWrongPincode() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupViewProtocol.self, method: "didReceiveWrongPincode()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_PinSetupViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_RecommendedValidatorListViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -24042,30 +22948,29 @@ import UIKit return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - - @discardableResult - func didRequestBiometryUsage(biometryType: M1, completionBlock: M2) -> Cuckoo.__DoNotUse<(AvailableBiometryType, (Bool) -> Void), Void> where M1.MatchedType == AvailableBiometryType, M2.MatchedType == (Bool) -> Void { - let matchers: [Cuckoo.ParameterMatcher<(AvailableBiometryType, (Bool) -> Void)>] = [wrap(matchable: biometryType) { $0.0 }, wrap(matchable: completionBlock) { $0.1 }] - return cuckoo_manager.verify("didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + @discardableResult - func didChangeAccessoryState(enabled: M1, availableBiometryType: M2) -> Cuckoo.__DoNotUse<(Bool, AvailableBiometryType), Void> where M1.MatchedType == Bool, M2.MatchedType == AvailableBiometryType { - let matchers: [Cuckoo.ParameterMatcher<(Bool, AvailableBiometryType)>] = [wrap(matchable: enabled) { $0.0 }, wrap(matchable: availableBiometryType) { $0.1 }] - return cuckoo_manager.verify("didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(RecommendedValidatorListViewModelProtocol), Void> where M1.MatchedType == RecommendedValidatorListViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(RecommendedValidatorListViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceive(viewModel: RecommendedValidatorListViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveWrongPincode() -> Cuckoo.__DoNotUse<(), Void> { + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didReceiveWrongPincode()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class PinSetupViewProtocolStub: PinSetupViewProtocol { + class RecommendedValidatorListViewProtocolStub: RecommendedValidatorListViewProtocol { @@ -24084,26 +22989,31 @@ import UIKit } } + - - - + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } + - func didRequestBiometryUsage(biometryType: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didChangeAccessoryState(enabled: Bool, availableBiometryType: AvailableBiometryType) { + func didReceive(viewModel: RecommendedValidatorListViewModelProtocol) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveWrongPincode() { + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -24111,19 +23021,19 @@ import UIKit - class MockPinSetupPresenterProtocol: PinSetupPresenterProtocol, Cuckoo.ProtocolMock { + class MockRecommendedValidatorListPresenterProtocol: RecommendedValidatorListPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = PinSetupPresenterProtocol + typealias MocksType = RecommendedValidatorListPresenterProtocol - typealias Stubbing = __StubbingProxy_PinSetupPresenterProtocol - typealias Verification = __VerificationProxy_PinSetupPresenterProtocol + typealias Stubbing = __StubbingProxy_RecommendedValidatorListPresenterProtocol + typealias Verification = __VerificationProxy_RecommendedValidatorListPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: PinSetupPresenterProtocol? + private var __defaultImplStub: RecommendedValidatorListPresenterProtocol? - func enableDefaultImplementation(_ stub: PinSetupPresenterProtocol) { + func enableDefaultImplementation(_ stub: RecommendedValidatorListPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -24136,66 +23046,51 @@ import UIKit - func start() { + func setup() { - return cuckoo_manager.call("start()", + return cuckoo_manager.call("setup()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.start()) + defaultCall: __defaultImplStub!.setup()) } - func cancel() { + func selectedValidatorAt(index: Int) { - return cuckoo_manager.call("cancel()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("selectedValidatorAt(index: Int)", + parameters: (index), + escapingParameters: (index), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.cancel()) + defaultCall: __defaultImplStub!.selectedValidatorAt(index: index)) } - func activateBiometricAuth() { + func proceed() { - return cuckoo_manager.call("activateBiometricAuth()", + return cuckoo_manager.call("proceed()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activateBiometricAuth()) - - } - - - - func submit(pin: String) { - - return cuckoo_manager.call("submit(pin: String)", - parameters: (pin), - escapingParameters: (pin), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.submit(pin: pin)) + defaultCall: __defaultImplStub!.proceed()) } - struct __StubbingProxy_PinSetupPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_RecommendedValidatorListPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -24203,29 +23098,24 @@ import UIKit } - func start() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupPresenterProtocol.self, method: "start()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func cancel() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupPresenterProtocol.self, method: "cancel()", parameterMatchers: matchers)) + func selectedValidatorAt(index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListPresenterProtocol.self, method: "selectedValidatorAt(index: Int)", parameterMatchers: matchers)) } - func activateBiometricAuth() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupPresenterProtocol.self, method: "activateBiometricAuth()", parameterMatchers: matchers)) - } - - func submit(pin: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: pin) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupPresenterProtocol.self, method: "submit(pin: String)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } } - struct __VerificationProxy_PinSetupPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_RecommendedValidatorListPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -24240,33 +23130,27 @@ import UIKit @discardableResult - func start() -> Cuckoo.__DoNotUse<(), Void> { + func setup() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("start()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func cancel() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("cancel()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectedValidatorAt(index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("selectedValidatorAt(index: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func activateBiometricAuth() -> Cuckoo.__DoNotUse<(), Void> { + func proceed() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("activateBiometricAuth()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func submit(pin: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: pin) { $0 }] - return cuckoo_manager.verify("submit(pin: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class PinSetupPresenterProtocolStub: PinSetupPresenterProtocol { + class RecommendedValidatorListPresenterProtocolStub: RecommendedValidatorListPresenterProtocol { @@ -24274,25 +23158,19 @@ import UIKit - func start() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func cancel() { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func activateBiometricAuth() { + func selectedValidatorAt(index: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func submit(pin: String) { + func proceed() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -24300,19 +23178,19 @@ import UIKit - class MockPinSetupInteractorInputProtocol: PinSetupInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockRecommendedValidatorListWireframeProtocol: RecommendedValidatorListWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = PinSetupInteractorInputProtocol + typealias MocksType = RecommendedValidatorListWireframeProtocol - typealias Stubbing = __StubbingProxy_PinSetupInteractorInputProtocol - typealias Verification = __VerificationProxy_PinSetupInteractorInputProtocol + typealias Stubbing = __StubbingProxy_RecommendedValidatorListWireframeProtocol + typealias Verification = __VerificationProxy_RecommendedValidatorListWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: PinSetupInteractorInputProtocol? + private var __defaultImplStub: RecommendedValidatorListWireframeProtocol? - func enableDefaultImplementation(_ stub: PinSetupInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: RecommendedValidatorListWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -24325,21 +23203,36 @@ import UIKit - func process(pin: String) { + func present(_ validatorInfo: SelectedValidatorInfo, from view: RecommendedValidatorListViewProtocol?) { - return cuckoo_manager.call("process(pin: String)", - parameters: (pin), - escapingParameters: (pin), + return cuckoo_manager.call("present(_: SelectedValidatorInfo, from: RecommendedValidatorListViewProtocol?)", + parameters: (validatorInfo, view), + escapingParameters: (validatorInfo, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.process(pin: pin)) + defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) + + } + + + + func proceed(from view: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int) { + + return cuckoo_manager.call("proceed(from: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", + parameters: (view, targets, maxTargets), + escapingParameters: (view, targets, maxTargets), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.proceed(from: view, targets: targets, maxTargets: maxTargets)) } - struct __StubbingProxy_PinSetupInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_RecommendedValidatorListWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -24347,14 +23240,19 @@ import UIKit } - func process(pin: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: pin) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupInteractorInputProtocol.self, method: "process(pin: String)", parameterMatchers: matchers)) + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorInfo, RecommendedValidatorListViewProtocol?)> where M1.MatchedType == SelectedValidatorInfo, M2.OptionalMatchedType == RecommendedValidatorListViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo, RecommendedValidatorListViewProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListWireframeProtocol.self, method: "present(_: SelectedValidatorInfo, from: RecommendedValidatorListViewProtocol?)", parameterMatchers: matchers)) + } + + func proceed(from view: M1, targets: M2, maxTargets: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(RecommendedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)> where M1.OptionalMatchedType == RecommendedValidatorListViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(RecommendedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: targets) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListWireframeProtocol.self, method: "proceed(from: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", parameterMatchers: matchers)) } } - struct __VerificationProxy_PinSetupInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_RecommendedValidatorListWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -24369,15 +23267,21 @@ import UIKit @discardableResult - func process(pin: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: pin) { $0 }] - return cuckoo_manager.verify("process(pin: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(SelectedValidatorInfo, RecommendedValidatorListViewProtocol?), Void> where M1.MatchedType == SelectedValidatorInfo, M2.OptionalMatchedType == RecommendedValidatorListViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo, RecommendedValidatorListViewProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("present(_: SelectedValidatorInfo, from: RecommendedValidatorListViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func proceed(from view: M1, targets: M2, maxTargets: M3) -> Cuckoo.__DoNotUse<(RecommendedValidatorListViewProtocol?, [SelectedValidatorInfo], Int), Void> where M1.OptionalMatchedType == RecommendedValidatorListViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(RecommendedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: targets) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] + return cuckoo_manager.verify("proceed(from: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class PinSetupInteractorInputProtocolStub: PinSetupInteractorInputProtocol { + class RecommendedValidatorListWireframeProtocolStub: RecommendedValidatorListWireframeProtocol { @@ -24385,84 +23289,237 @@ import UIKit - func process(pin: String) { + func present(_ validatorInfo: SelectedValidatorInfo, from view: RecommendedValidatorListViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func proceed(from view: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet - class MockPinSetupInteractorOutputProtocol: PinSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { +import BigInt +import Foundation +import SoraFoundation + + + class MockSelectValidatorsConfirmViewProtocol: SelectValidatorsConfirmViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = PinSetupInteractorOutputProtocol + typealias MocksType = SelectValidatorsConfirmViewProtocol - typealias Stubbing = __StubbingProxy_PinSetupInteractorOutputProtocol - typealias Verification = __VerificationProxy_PinSetupInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmViewProtocol + typealias Verification = __VerificationProxy_SelectValidatorsConfirmViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: PinSetupInteractorOutputProtocol? + private var __defaultImplStub: SelectValidatorsConfirmViewProtocol? - func enableDefaultImplementation(_ stub: PinSetupInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsConfirmViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } - func didSavePin() { + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } - return cuckoo_manager.call("didSavePin()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didSavePin()) + } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } + + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } } - func didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void) { + var loadableContentView: UIView! { + get { + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) + } - return cuckoo_manager.call("didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", - parameters: (type, completionBlock), - escapingParameters: (type, completionBlock), + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) + } + + } + + + + + + + + func didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel) { + + return cuckoo_manager.call("didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel)", + parameters: (confirmationViewModel), + escapingParameters: (confirmationViewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStartWaitingBiometryDecision(type: type, completionBlock: completionBlock)) + defaultCall: __defaultImplStub!.didReceive(confirmationViewModel: confirmationViewModel)) } - func didChangeState(from: PinSetupInteractor.PinSetupState) { + func didReceive(hintsViewModel: LocalizableResource<[String]>) { - return cuckoo_manager.call("didChangeState(from: PinSetupInteractor.PinSetupState)", - parameters: (from), - escapingParameters: (from), + return cuckoo_manager.call("didReceive(hintsViewModel: LocalizableResource<[String]>)", + parameters: (hintsViewModel), + escapingParameters: (hintsViewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didChangeState(from: from)) + defaultCall: __defaultImplStub!.didReceive(hintsViewModel: hintsViewModel)) + + } + + + + func didReceive(amountViewModel: LocalizableResource?) { + + return cuckoo_manager.call("didReceive(amountViewModel: LocalizableResource?)", + parameters: (amountViewModel), + escapingParameters: (amountViewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(amountViewModel: amountViewModel)) + + } + + + + func didReceive(feeViewModel: LocalizableResource?) { + + return cuckoo_manager.call("didReceive(feeViewModel: LocalizableResource?)", + parameters: (feeViewModel), + escapingParameters: (feeViewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(feeViewModel: feeViewModel)) + + } + + + + public func applyLocalization() { + + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.applyLocalization()) + + } + + + + func didStartLoading() { + + return cuckoo_manager.call("didStartLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStartLoading()) + + } + + + + func didStopLoading() { + + return cuckoo_manager.call("didStopLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStopLoading()) } - struct __StubbingProxy_PinSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsConfirmViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -24470,24 +23527,69 @@ import UIKit } - func didSavePin() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") + } + + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") + } + + + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") + } + + + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") + } + + + func didReceive(confirmationViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectValidatorsConfirmViewModel)> where M1.MatchedType == SelectValidatorsConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsConfirmViewModel)>] = [wrap(matchable: confirmationViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel)", parameterMatchers: matchers)) + } + + func didReceive(hintsViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource<[String]>)> where M1.MatchedType == LocalizableResource<[String]> { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource<[String]>)>] = [wrap(matchable: hintsViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didReceive(hintsViewModel: LocalizableResource<[String]>)", parameterMatchers: matchers)) + } + + func didReceive(amountViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: amountViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didReceive(amountViewModel: LocalizableResource?)", parameterMatchers: matchers)) + } + + func didReceive(feeViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: feeViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didReceive(feeViewModel: LocalizableResource?)", parameterMatchers: matchers)) + } + + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupInteractorOutputProtocol.self, method: "didSavePin()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } - func didStartWaitingBiometryDecision(type: M1, completionBlock: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(AvailableBiometryType, (Bool) -> Void)> where M1.MatchedType == AvailableBiometryType, M2.MatchedType == (Bool) -> Void { - let matchers: [Cuckoo.ParameterMatcher<(AvailableBiometryType, (Bool) -> Void)>] = [wrap(matchable: type) { $0.0 }, wrap(matchable: completionBlock) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupInteractorOutputProtocol.self, method: "didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", parameterMatchers: matchers)) + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) } - func didChangeState(from: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PinSetupInteractor.PinSetupState)> where M1.MatchedType == PinSetupInteractor.PinSetupState { - let matchers: [Cuckoo.ParameterMatcher<(PinSetupInteractor.PinSetupState)>] = [wrap(matchable: from) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupInteractorOutputProtocol.self, method: "didChangeState(from: PinSetupInteractor.PinSetupState)", parameterMatchers: matchers)) + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_PinSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsConfirmViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -24499,30 +23601,126 @@ import UIKit } + + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func didSavePin() -> Cuckoo.__DoNotUse<(), Void> { + func didReceive(confirmationViewModel: M1) -> Cuckoo.__DoNotUse<(SelectValidatorsConfirmViewModel), Void> where M1.MatchedType == SelectValidatorsConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsConfirmViewModel)>] = [wrap(matchable: confirmationViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(hintsViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource<[String]>), Void> where M1.MatchedType == LocalizableResource<[String]> { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource<[String]>)>] = [wrap(matchable: hintsViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(hintsViewModel: LocalizableResource<[String]>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(amountViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: amountViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(amountViewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(feeViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: feeViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(feeViewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didSavePin()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStartWaitingBiometryDecision(type: M1, completionBlock: M2) -> Cuckoo.__DoNotUse<(AvailableBiometryType, (Bool) -> Void), Void> where M1.MatchedType == AvailableBiometryType, M2.MatchedType == (Bool) -> Void { - let matchers: [Cuckoo.ParameterMatcher<(AvailableBiometryType, (Bool) -> Void)>] = [wrap(matchable: type) { $0.0 }, wrap(matchable: completionBlock) { $0.1 }] - return cuckoo_manager.verify("didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didChangeState(from: M1) -> Cuckoo.__DoNotUse<(PinSetupInteractor.PinSetupState), Void> where M1.MatchedType == PinSetupInteractor.PinSetupState { - let matchers: [Cuckoo.ParameterMatcher<(PinSetupInteractor.PinSetupState)>] = [wrap(matchable: from) { $0 }] - return cuckoo_manager.verify("didChangeState(from: PinSetupInteractor.PinSetupState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class PinSetupInteractorOutputProtocolStub: PinSetupInteractorOutputProtocol { + class SelectValidatorsConfirmViewProtocolStub: SelectValidatorsConfirmViewProtocol { + + + + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + + + + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + + } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } + + + + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } @@ -24530,19 +23728,43 @@ import UIKit - func didSavePin() { + func didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartWaitingBiometryDecision(type: AvailableBiometryType, completionBlock: @escaping (Bool) -> Void) { + func didReceive(hintsViewModel: LocalizableResource<[String]>) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didChangeState(from: PinSetupInteractor.PinSetupState) { + func didReceive(amountViewModel: LocalizableResource?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceive(feeViewModel: LocalizableResource?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + public func applyLocalization() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStartLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStopLoading() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -24550,19 +23772,19 @@ import UIKit - class MockPinSetupWireframeProtocol: PinSetupWireframeProtocol, Cuckoo.ProtocolMock { + class MockSelectValidatorsConfirmPresenterProtocol: SelectValidatorsConfirmPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = PinSetupWireframeProtocol + typealias MocksType = SelectValidatorsConfirmPresenterProtocol - typealias Stubbing = __StubbingProxy_PinSetupWireframeProtocol - typealias Verification = __VerificationProxy_PinSetupWireframeProtocol + typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmPresenterProtocol + typealias Verification = __VerificationProxy_SelectValidatorsConfirmPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: PinSetupWireframeProtocol? + private var __defaultImplStub: SelectValidatorsConfirmPresenterProtocol? - func enableDefaultImplementation(_ stub: PinSetupWireframeProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsConfirmPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -24575,36 +23797,66 @@ import UIKit - func showMain(from view: PinSetupViewProtocol?) { + func setup() { - return cuckoo_manager.call("showMain(from: PinSetupViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showMain(from: view)) + defaultCall: __defaultImplStub!.setup()) } - func showSignup(from view: PinSetupViewProtocol?) { + func selectWalletAccount() { - return cuckoo_manager.call("showSignup(from: PinSetupViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("selectWalletAccount()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showSignup(from: view)) + defaultCall: __defaultImplStub!.selectWalletAccount()) + + } + + + + func selectPayoutAccount() { + + return cuckoo_manager.call("selectPayoutAccount()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.selectPayoutAccount()) + + } + + + + func proceed() { + + return cuckoo_manager.call("proceed()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.proceed()) } - struct __StubbingProxy_PinSetupWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsConfirmPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -24612,19 +23864,29 @@ import UIKit } - func showMain(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PinSetupViewProtocol?)> where M1.OptionalMatchedType == PinSetupViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(PinSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupWireframeProtocol.self, method: "showMain(from: PinSetupViewProtocol?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func showSignup(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PinSetupViewProtocol?)> where M1.OptionalMatchedType == PinSetupViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(PinSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockPinSetupWireframeProtocol.self, method: "showSignup(from: PinSetupViewProtocol?)", parameterMatchers: matchers)) + func selectWalletAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmPresenterProtocol.self, method: "selectWalletAccount()", parameterMatchers: matchers)) + } + + func selectPayoutAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmPresenterProtocol.self, method: "selectPayoutAccount()", parameterMatchers: matchers)) + } + + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } } - struct __VerificationProxy_PinSetupWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsConfirmPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -24639,21 +23901,33 @@ import UIKit @discardableResult - func showMain(from view: M1) -> Cuckoo.__DoNotUse<(PinSetupViewProtocol?), Void> where M1.OptionalMatchedType == PinSetupViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(PinSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showMain(from: PinSetupViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showSignup(from view: M1) -> Cuckoo.__DoNotUse<(PinSetupViewProtocol?), Void> where M1.OptionalMatchedType == PinSetupViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(PinSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showSignup(from: PinSetupViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectWalletAccount() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectWalletAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func selectPayoutAccount() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectPayoutAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func proceed() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class PinSetupWireframeProtocolStub: PinSetupWireframeProtocol { + class SelectValidatorsConfirmPresenterProtocolStub: SelectValidatorsConfirmPresenterProtocol { @@ -24661,38 +23935,45 @@ import UIKit - func showMain(from view: PinSetupViewProtocol?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showSignup(from view: PinSetupViewProtocol?) { + func selectWalletAccount() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func selectPayoutAccount() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func proceed() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import UIKit - - class MockRootPresenterProtocol: RootPresenterProtocol, Cuckoo.ProtocolMock { + class MockSelectValidatorsConfirmInteractorInputProtocol: SelectValidatorsConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = RootPresenterProtocol + typealias MocksType = SelectValidatorsConfirmInteractorInputProtocol - typealias Stubbing = __StubbingProxy_RootPresenterProtocol - typealias Verification = __VerificationProxy_RootPresenterProtocol + typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmInteractorInputProtocol + typealias Verification = __VerificationProxy_SelectValidatorsConfirmInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: RootPresenterProtocol? + private var __defaultImplStub: SelectValidatorsConfirmInteractorInputProtocol? - func enableDefaultImplementation(_ stub: RootPresenterProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsConfirmInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -24705,21 +23986,51 @@ import UIKit - func loadOnLaunch() { + func setup() { - return cuckoo_manager.call("loadOnLaunch()", + return cuckoo_manager.call("setup()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.loadOnLaunch()) + defaultCall: __defaultImplStub!.setup()) + + } + + + + func submitNomination() { + + return cuckoo_manager.call("submitNomination()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.submitNomination()) + + } + + + + func estimateFee() { + + return cuckoo_manager.call("estimateFee()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.estimateFee()) } - struct __StubbingProxy_RootPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -24727,14 +24038,24 @@ import UIKit } - func loadOnLaunch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRootPresenterProtocol.self, method: "loadOnLaunch()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func submitNomination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorInputProtocol.self, method: "submitNomination()", parameterMatchers: matchers)) + } + + func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) } } - struct __VerificationProxy_RootPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -24749,15 +24070,27 @@ import UIKit @discardableResult - func loadOnLaunch() -> Cuckoo.__DoNotUse<(), Void> { + func setup() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("loadOnLaunch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func submitNomination() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("submitNomination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class RootPresenterProtocolStub: RootPresenterProtocol { + class SelectValidatorsConfirmInteractorInputProtocolStub: SelectValidatorsConfirmInteractorInputProtocol { @@ -24765,27 +24098,39 @@ import UIKit - func loadOnLaunch() { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockRootWireframeProtocol: RootWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = RootWireframeProtocol - typealias Stubbing = __StubbingProxy_RootWireframeProtocol - typealias Verification = __VerificationProxy_RootWireframeProtocol + func submitNomination() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func estimateFee() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + + + class MockSelectValidatorsConfirmInteractorOutputProtocol: SelectValidatorsConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = SelectValidatorsConfirmInteractorOutputProtocol + + typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmInteractorOutputProtocol + typealias Verification = __VerificationProxy_SelectValidatorsConfirmInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: RootWireframeProtocol? + private var __defaultImplStub: SelectValidatorsConfirmInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: RootWireframeProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsConfirmInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -24798,66 +24143,186 @@ import UIKit - func showLocalAuthentication(on view: UIWindow) { + func didReceiveModel(result: Result) { - return cuckoo_manager.call("showLocalAuthentication(on: UIWindow)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceiveModel(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showLocalAuthentication(on: view)) + defaultCall: __defaultImplStub!.didReceiveModel(result: result)) } - func showOnboarding(on view: UIWindow) { + func didReceivePrice(result: Result) { - return cuckoo_manager.call("showOnboarding(on: UIWindow)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceivePrice(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showOnboarding(on: view)) + defaultCall: __defaultImplStub!.didReceivePrice(result: result)) } - func showPincodeSetup(on view: UIWindow) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("showPincodeSetup(on: UIWindow)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showPincodeSetup(on: view)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - func showBroken(on view: UIWindow) { + func didReceiveMinBond(result: Result) { - return cuckoo_manager.call("showBroken(on: UIWindow)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceiveMinBond(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showBroken(on: view)) + defaultCall: __defaultImplStub!.didReceiveMinBond(result: result)) + + } + + + + func didReceiveCounterForNominators(result: Result) { + + return cuckoo_manager.call("didReceiveCounterForNominators(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveCounterForNominators(result: result)) + + } + + + + func didReceiveMaxNominatorsCount(result: Result) { + + return cuckoo_manager.call("didReceiveMaxNominatorsCount(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveMaxNominatorsCount(result: result)) + + } + + + + func didReceiveStakingDuration(result: Result) { + + return cuckoo_manager.call("didReceiveStakingDuration(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveStakingDuration(result: result)) + + } + + + + func didStartNomination() { + + return cuckoo_manager.call("didStartNomination()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStartNomination()) + + } + + + + func didCompleteNomination(txHash: String) { + + return cuckoo_manager.call("didCompleteNomination(txHash: String)", + parameters: (txHash), + escapingParameters: (txHash), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didCompleteNomination(txHash: txHash)) + + } + + + + func didFailNomination(error: Error) { + + return cuckoo_manager.call("didFailNomination(error: Error)", + parameters: (error), + escapingParameters: (error), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didFailNomination(error: error)) + + } + + + + func didReceive(paymentInfo: RuntimeDispatchInfo) { + + return cuckoo_manager.call("didReceive(paymentInfo: RuntimeDispatchInfo)", + parameters: (paymentInfo), + escapingParameters: (paymentInfo), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(paymentInfo: paymentInfo)) + + } + + + + func didReceive(feeError: Error) { + + return cuckoo_manager.call("didReceive(feeError: Error)", + parameters: (feeError), + escapingParameters: (feeError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(feeError: feeError)) } - struct __StubbingProxy_RootWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -24865,29 +24330,69 @@ import UIKit } - func showLocalAuthentication(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(UIWindow)> where M1.MatchedType == UIWindow { - let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockRootWireframeProtocol.self, method: "showLocalAuthentication(on: UIWindow)", parameterMatchers: matchers)) + func didReceiveModel(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveModel(result: Result)", parameterMatchers: matchers)) } - func showOnboarding(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(UIWindow)> where M1.MatchedType == UIWindow { - let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockRootWireframeProtocol.self, method: "showOnboarding(on: UIWindow)", parameterMatchers: matchers)) + func didReceivePrice(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceivePrice(result: Result)", parameterMatchers: matchers)) } - func showPincodeSetup(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(UIWindow)> where M1.MatchedType == UIWindow { - let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockRootWireframeProtocol.self, method: "showPincodeSetup(on: UIWindow)", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - func showBroken(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(UIWindow)> where M1.MatchedType == UIWindow { - let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockRootWireframeProtocol.self, method: "showBroken(on: UIWindow)", parameterMatchers: matchers)) + func didReceiveMinBond(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveMinBond(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveCounterForNominators(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveCounterForNominators(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveMaxNominatorsCount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveMaxNominatorsCount(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveStakingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveStakingDuration(result: Result)", parameterMatchers: matchers)) + } + + func didStartNomination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didStartNomination()", parameterMatchers: matchers)) + } + + func didCompleteNomination(txHash: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: txHash) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didCompleteNomination(txHash: String)", parameterMatchers: matchers)) + } + + func didFailNomination(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didFailNomination(error: Error)", parameterMatchers: matchers)) + } + + func didReceive(paymentInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RuntimeDispatchInfo)> where M1.MatchedType == RuntimeDispatchInfo { + let matchers: [Cuckoo.ParameterMatcher<(RuntimeDispatchInfo)>] = [wrap(matchable: paymentInfo) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceive(paymentInfo: RuntimeDispatchInfo)", parameterMatchers: matchers)) + } + + func didReceive(feeError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: feeError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceive(feeError: Error)", parameterMatchers: matchers)) } } - struct __VerificationProxy_RootWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -24902,33 +24407,81 @@ import UIKit @discardableResult - func showLocalAuthentication(on view: M1) -> Cuckoo.__DoNotUse<(UIWindow), Void> where M1.MatchedType == UIWindow { - let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showLocalAuthentication(on: UIWindow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveModel(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveModel(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showOnboarding(on view: M1) -> Cuckoo.__DoNotUse<(UIWindow), Void> where M1.MatchedType == UIWindow { - let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showOnboarding(on: UIWindow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePrice(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePrice(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showPincodeSetup(on view: M1) -> Cuckoo.__DoNotUse<(UIWindow), Void> where M1.MatchedType == UIWindow { - let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showPincodeSetup(on: UIWindow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showBroken(on view: M1) -> Cuckoo.__DoNotUse<(UIWindow), Void> where M1.MatchedType == UIWindow { - let matchers: [Cuckoo.ParameterMatcher<(UIWindow)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showBroken(on: UIWindow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveMinBond(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMinBond(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveCounterForNominators(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveCounterForNominators(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveMaxNominatorsCount(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMaxNominatorsCount(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveStakingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didStartNomination() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartNomination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didCompleteNomination(txHash: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: txHash) { $0 }] + return cuckoo_manager.verify("didCompleteNomination(txHash: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didFailNomination(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return cuckoo_manager.verify("didFailNomination(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(paymentInfo: M1) -> Cuckoo.__DoNotUse<(RuntimeDispatchInfo), Void> where M1.MatchedType == RuntimeDispatchInfo { + let matchers: [Cuckoo.ParameterMatcher<(RuntimeDispatchInfo)>] = [wrap(matchable: paymentInfo) { $0 }] + return cuckoo_manager.verify("didReceive(paymentInfo: RuntimeDispatchInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(feeError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: feeError) { $0 }] + return cuckoo_manager.verify("didReceive(feeError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class RootWireframeProtocolStub: RootWireframeProtocol { + class SelectValidatorsConfirmInteractorOutputProtocolStub: SelectValidatorsConfirmInteractorOutputProtocol { @@ -24936,25 +24489,73 @@ import UIKit - func showLocalAuthentication(on view: UIWindow) { + func didReceiveModel(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showOnboarding(on view: UIWindow) { + func didReceivePrice(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showPincodeSetup(on view: UIWindow) { + func didReceiveAccountInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showBroken(on view: UIWindow) { + func didReceiveMinBond(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveCounterForNominators(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveMaxNominatorsCount(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveStakingDuration(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStartNomination() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didCompleteNomination(txHash: String) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didFailNomination(error: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceive(paymentInfo: RuntimeDispatchInfo) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceive(feeError: Error) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -24962,19 +24563,19 @@ import UIKit - class MockRootInteractorInputProtocol: RootInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockSelectValidatorsConfirmWireframeProtocol: SelectValidatorsConfirmWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = RootInteractorInputProtocol + typealias MocksType = SelectValidatorsConfirmWireframeProtocol - typealias Stubbing = __StubbingProxy_RootInteractorInputProtocol - typealias Verification = __VerificationProxy_RootInteractorInputProtocol + typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmWireframeProtocol + typealias Verification = __VerificationProxy_SelectValidatorsConfirmWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: RootInteractorInputProtocol? + private var __defaultImplStub: SelectValidatorsConfirmWireframeProtocol? - func enableDefaultImplementation(_ stub: RootInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsConfirmWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -24987,36 +24588,51 @@ import UIKit - func setup() { + func complete(from view: SelectValidatorsConfirmViewProtocol?) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("complete(from: SelectValidatorsConfirmViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.complete(from: view)) } - func decideModuleSynchroniously() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("decideModuleSynchroniously()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.decideModuleSynchroniously()) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_RootInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsConfirmWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -25024,19 +24640,24 @@ import UIKit } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectValidatorsConfirmViewProtocol?)> where M1.OptionalMatchedType == SelectValidatorsConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmWireframeProtocol.self, method: "complete(from: SelectValidatorsConfirmViewProtocol?)", parameterMatchers: matchers)) } - func decideModuleSynchroniously() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorInputProtocol.self, method: "decideModuleSynchroniously()", parameterMatchers: matchers)) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_RootInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsConfirmWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -25051,21 +24672,27 @@ import UIKit @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func complete(from view: M1) -> Cuckoo.__DoNotUse<(SelectValidatorsConfirmViewProtocol?), Void> where M1.OptionalMatchedType == SelectValidatorsConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("complete(from: SelectValidatorsConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func decideModuleSynchroniously() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("decideModuleSynchroniously()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class RootInteractorInputProtocolStub: RootInteractorInputProtocol { + class SelectValidatorsConfirmWireframeProtocolStub: SelectValidatorsConfirmWireframeProtocol { @@ -25073,258 +24700,99 @@ import UIKit - func setup() { + func complete(from view: SelectValidatorsConfirmViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func decideModuleSynchroniously() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet - class MockRootInteractorOutputProtocol: RootInteractorOutputProtocol, Cuckoo.ProtocolMock { +import Foundation +import SoraFoundation + + + class MockSelectValidatorsStartViewProtocol: SelectValidatorsStartViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = RootInteractorOutputProtocol + typealias MocksType = SelectValidatorsStartViewProtocol - typealias Stubbing = __StubbingProxy_RootInteractorOutputProtocol - typealias Verification = __VerificationProxy_RootInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_SelectValidatorsStartViewProtocol + typealias Verification = __VerificationProxy_SelectValidatorsStartViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: RootInteractorOutputProtocol? + private var __defaultImplStub: SelectValidatorsStartViewProtocol? - func enableDefaultImplementation(_ stub: RootInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsStartViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } - func didDecideOnboarding() { - - return cuckoo_manager.call("didDecideOnboarding()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didDecideOnboarding()) - - } - - - - func didDecideLocalAuthentication() { - - return cuckoo_manager.call("didDecideLocalAuthentication()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didDecideLocalAuthentication()) - - } - - - - func didDecidePincodeSetup() { - - return cuckoo_manager.call("didDecidePincodeSetup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didDecidePincodeSetup()) - - } - - - - func didDecideBroken() { - - return cuckoo_manager.call("didDecideBroken()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didDecideBroken()) - - } - - - struct __StubbingProxy_RootInteractorOutputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func didDecideOnboarding() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, method: "didDecideOnboarding()", parameterMatchers: matchers)) - } - - func didDecideLocalAuthentication() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, method: "didDecideLocalAuthentication()", parameterMatchers: matchers)) - } - - func didDecidePincodeSetup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, method: "didDecidePincodeSetup()", parameterMatchers: matchers)) - } - - func didDecideBroken() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, method: "didDecideBroken()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_RootInteractorOutputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func didDecideOnboarding() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didDecideOnboarding()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didDecideLocalAuthentication() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didDecideLocalAuthentication()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didDecidePincodeSetup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didDecidePincodeSetup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didDecideBroken() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didDecideBroken()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class RootInteractorOutputProtocolStub: RootInteractorOutputProtocol { - - - - - - - - func didDecideOnboarding() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didDecideLocalAuthentication() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didDecidePincodeSetup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didDecideBroken() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - -import Cuckoo -@testable import novawallet - -import Foundation -import UIKit.UIImage - - - class MockSettingsViewProtocol: SettingsViewProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = SettingsViewProtocol - - typealias Stubbing = __StubbingProxy_SettingsViewProtocol - typealias Verification = __VerificationProxy_SettingsViewProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: SettingsViewProtocol? - - func enableDefaultImplementation(_ stub: SettingsViewProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - var isSetup: Bool { + var controller: UIViewController { get { - return cuckoo_manager.getter("isSetup", + return cuckoo_manager.getter("controller", superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.isSetup) + defaultCall: __defaultImplStub!.controller) } } - var controller: UIViewController { + public var localizationManager: LocalizationManagerProtocol? { get { - return cuckoo_manager.getter("controller", + return cuckoo_manager.getter("localizationManager", superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.controller) + defaultCall: __defaultImplStub!.localizationManager) + } + + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) } } @@ -25335,36 +24803,36 @@ import UIKit.UIImage - func reload(sections: [(SettingsSection, [SettingsCellViewModel])]) { + func didReceive(viewModel: SelectValidatorsStartViewModel) { - return cuckoo_manager.call("reload(sections: [(SettingsSection, [SettingsCellViewModel])])", - parameters: (sections), - escapingParameters: (sections), + return cuckoo_manager.call("didReceive(viewModel: SelectValidatorsStartViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload(sections: sections)) + defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) } - func didLoad(userViewModel: SettingsAccountViewModel) { + public func applyLocalization() { - return cuckoo_manager.call("didLoad(userViewModel: SettingsAccountViewModel)", - parameters: (userViewModel), - escapingParameters: (userViewModel), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didLoad(userViewModel: userViewModel)) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_SettingsViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsStartViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -25372,29 +24840,34 @@ import UIKit.UIImage } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - func reload(sections: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([(SettingsSection, [SettingsCellViewModel])])> where M1.MatchedType == [(SettingsSection, [SettingsCellViewModel])] { - let matchers: [Cuckoo.ParameterMatcher<([(SettingsSection, [SettingsCellViewModel])])>] = [wrap(matchable: sections) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsViewProtocol.self, method: "reload(sections: [(SettingsSection, [SettingsCellViewModel])])", parameterMatchers: matchers)) + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func didLoad(userViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SettingsAccountViewModel)> where M1.MatchedType == SettingsAccountViewModel { - let matchers: [Cuckoo.ParameterMatcher<(SettingsAccountViewModel)>] = [wrap(matchable: userViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsViewProtocol.self, method: "didLoad(userViewModel: SettingsAccountViewModel)", parameterMatchers: matchers)) + + func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectValidatorsStartViewModel)> where M1.MatchedType == SelectValidatorsStartViewModel { + let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsStartViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartViewProtocol.self, method: "didReceive(viewModel: SelectValidatorsStartViewModel)", parameterMatchers: matchers)) + } + + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SettingsViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsStartViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -25416,24 +24889,29 @@ import UIKit.UIImage return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func reload(sections: M1) -> Cuckoo.__DoNotUse<([(SettingsSection, [SettingsCellViewModel])]), Void> where M1.MatchedType == [(SettingsSection, [SettingsCellViewModel])] { - let matchers: [Cuckoo.ParameterMatcher<([(SettingsSection, [SettingsCellViewModel])])>] = [wrap(matchable: sections) { $0 }] - return cuckoo_manager.verify("reload(sections: [(SettingsSection, [SettingsCellViewModel])])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(SelectValidatorsStartViewModel), Void> where M1.MatchedType == SelectValidatorsStartViewModel { + let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsStartViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceive(viewModel: SelectValidatorsStartViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didLoad(userViewModel: M1) -> Cuckoo.__DoNotUse<(SettingsAccountViewModel), Void> where M1.MatchedType == SettingsAccountViewModel { - let matchers: [Cuckoo.ParameterMatcher<(SettingsAccountViewModel)>] = [wrap(matchable: userViewModel) { $0 }] - return cuckoo_manager.verify("didLoad(userViewModel: SettingsAccountViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SettingsViewProtocolStub: SettingsViewProtocol { + class SelectValidatorsStartViewProtocolStub: SelectValidatorsStartViewProtocol { @@ -25452,6 +24930,17 @@ import UIKit.UIImage } } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } @@ -25459,13 +24948,13 @@ import UIKit.UIImage - func reload(sections: [(SettingsSection, [SettingsCellViewModel])]) { + func didReceive(viewModel: SelectValidatorsStartViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didLoad(userViewModel: SettingsAccountViewModel) { + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -25473,39 +24962,25 @@ import UIKit.UIImage - class MockSettingsPresenterProtocol: SettingsPresenterProtocol, Cuckoo.ProtocolMock { + class MockSelectValidatorsStartPresenterProtocol: SelectValidatorsStartPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SettingsPresenterProtocol + typealias MocksType = SelectValidatorsStartPresenterProtocol - typealias Stubbing = __StubbingProxy_SettingsPresenterProtocol - typealias Verification = __VerificationProxy_SettingsPresenterProtocol + typealias Stubbing = __StubbingProxy_SelectValidatorsStartPresenterProtocol + typealias Verification = __VerificationProxy_SelectValidatorsStartPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SettingsPresenterProtocol? + private var __defaultImplStub: SelectValidatorsStartPresenterProtocol? - func enableDefaultImplementation(_ stub: SettingsPresenterProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsStartPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var appNameText: String { - get { - return cuckoo_manager.getter("appNameText", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.appNameText) - } - - } - @@ -25527,51 +25002,66 @@ import UIKit.UIImage - func actionRow(_ row: SettingsRow) { + func updateOnAppearance() { - return cuckoo_manager.call("actionRow(_: SettingsRow)", - parameters: (row), - escapingParameters: (row), + return cuckoo_manager.call("updateOnAppearance()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.actionRow(row)) + defaultCall: __defaultImplStub!.updateOnAppearance()) } - func handleWalletAction() { + func selectRecommendedValidators() { - return cuckoo_manager.call("handleWalletAction()", + return cuckoo_manager.call("selectRecommendedValidators()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.handleWalletAction()) + defaultCall: __defaultImplStub!.selectRecommendedValidators()) } - func handleSwitchAction() { + func selectCustomValidators() { - return cuckoo_manager.call("handleSwitchAction()", + return cuckoo_manager.call("selectCustomValidators()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.handleSwitchAction()) + defaultCall: __defaultImplStub!.selectCustomValidators()) + + } + + + + func selectLearnMore() { + + return cuckoo_manager.call("selectLearnMore()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.selectLearnMore()) } - struct __StubbingProxy_SettingsPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsStartPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -25579,34 +25069,34 @@ import UIKit.UIImage } - var appNameText: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "appNameText") + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func updateOnAppearance() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "updateOnAppearance()", parameterMatchers: matchers)) } - func actionRow(_ row: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SettingsRow)> where M1.MatchedType == SettingsRow { - let matchers: [Cuckoo.ParameterMatcher<(SettingsRow)>] = [wrap(matchable: row) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsPresenterProtocol.self, method: "actionRow(_: SettingsRow)", parameterMatchers: matchers)) + func selectRecommendedValidators() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "selectRecommendedValidators()", parameterMatchers: matchers)) } - func handleWalletAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func selectCustomValidators() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsPresenterProtocol.self, method: "handleWalletAction()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "selectCustomValidators()", parameterMatchers: matchers)) } - func handleSwitchAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func selectLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsPresenterProtocol.self, method: "handleSwitchAction()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "selectLearnMore()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SettingsPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsStartPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -25618,11 +25108,6 @@ import UIKit.UIImage } - - var appNameText: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "appNameText", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult @@ -25632,36 +25117,33 @@ import UIKit.UIImage } @discardableResult - func actionRow(_ row: M1) -> Cuckoo.__DoNotUse<(SettingsRow), Void> where M1.MatchedType == SettingsRow { - let matchers: [Cuckoo.ParameterMatcher<(SettingsRow)>] = [wrap(matchable: row) { $0 }] - return cuckoo_manager.verify("actionRow(_: SettingsRow)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func updateOnAppearance() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("updateOnAppearance()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func handleWalletAction() -> Cuckoo.__DoNotUse<(), Void> { + func selectRecommendedValidators() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handleWalletAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("selectRecommendedValidators()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func handleSwitchAction() -> Cuckoo.__DoNotUse<(), Void> { + func selectCustomValidators() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handleSwitchAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("selectCustomValidators()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func selectLearnMore() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SettingsPresenterProtocolStub: SettingsPresenterProtocol { - - - - var appNameText: String { - get { - return DefaultValueRegistry.defaultValue(for: (String).self) - } - - } + class SelectValidatorsStartPresenterProtocolStub: SelectValidatorsStartPresenterProtocol { @@ -25675,19 +25157,25 @@ import UIKit.UIImage - func actionRow(_ row: SettingsRow) { + func updateOnAppearance() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func handleWalletAction() { + func selectRecommendedValidators() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func handleSwitchAction() { + func selectCustomValidators() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func selectLearnMore() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -25695,19 +25183,19 @@ import UIKit.UIImage - class MockSettingsViewModelFactoryProtocol: SettingsViewModelFactoryProtocol, Cuckoo.ProtocolMock { + class MockSelectValidatorsStartInteractorInputProtocol: SelectValidatorsStartInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SettingsViewModelFactoryProtocol + typealias MocksType = SelectValidatorsStartInteractorInputProtocol - typealias Stubbing = __StubbingProxy_SettingsViewModelFactoryProtocol - typealias Verification = __VerificationProxy_SettingsViewModelFactoryProtocol + typealias Stubbing = __StubbingProxy_SelectValidatorsStartInteractorInputProtocol + typealias Verification = __VerificationProxy_SelectValidatorsStartInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SettingsViewModelFactoryProtocol? + private var __defaultImplStub: SelectValidatorsStartInteractorInputProtocol? - func enableDefaultImplementation(_ stub: SettingsViewModelFactoryProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsStartInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -25720,36 +25208,21 @@ import UIKit.UIImage - func createAccountViewModel(for wallet: MetaAccountModel) -> SettingsAccountViewModel { - - return cuckoo_manager.call("createAccountViewModel(for: MetaAccountModel) -> SettingsAccountViewModel", - parameters: (wallet), - escapingParameters: (wallet), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.createAccountViewModel(for: wallet)) - - } - - - - func createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])] { + func setup() { - return cuckoo_manager.call("createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])]", - parameters: (language, currency, locale), - escapingParameters: (language, currency, locale), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.createSectionViewModels(language: language, currency: currency, locale: locale)) + defaultCall: __defaultImplStub!.setup()) } - struct __StubbingProxy_SettingsViewModelFactoryProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsStartInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -25757,19 +25230,14 @@ import UIKit.UIImage } - func createAccountViewModel(for wallet: M1) -> Cuckoo.ProtocolStubFunction<(MetaAccountModel), SettingsAccountViewModel> where M1.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsViewModelFactoryProtocol.self, method: "createAccountViewModel(for: MetaAccountModel) -> SettingsAccountViewModel", parameterMatchers: matchers)) - } - - func createSectionViewModels(language: M1, currency: M2, locale: M3) -> Cuckoo.ProtocolStubFunction<(Language?, String?, Locale), [(SettingsSection, [SettingsCellViewModel])]> where M1.OptionalMatchedType == Language, M2.OptionalMatchedType == String, M3.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<(Language?, String?, Locale)>] = [wrap(matchable: language) { $0.0 }, wrap(matchable: currency) { $0.1 }, wrap(matchable: locale) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsViewModelFactoryProtocol.self, method: "createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])]", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SettingsViewModelFactoryProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsStartInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -25784,21 +25252,15 @@ import UIKit.UIImage @discardableResult - func createAccountViewModel(for wallet: M1) -> Cuckoo.__DoNotUse<(MetaAccountModel), SettingsAccountViewModel> where M1.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] - return cuckoo_manager.verify("createAccountViewModel(for: MetaAccountModel) -> SettingsAccountViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func createSectionViewModels(language: M1, currency: M2, locale: M3) -> Cuckoo.__DoNotUse<(Language?, String?, Locale), [(SettingsSection, [SettingsCellViewModel])]> where M1.OptionalMatchedType == Language, M2.OptionalMatchedType == String, M3.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<(Language?, String?, Locale)>] = [wrap(matchable: language) { $0.0 }, wrap(matchable: currency) { $0.1 }, wrap(matchable: locale) { $0.2 }] - return cuckoo_manager.verify("createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])]", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SettingsViewModelFactoryProtocolStub: SettingsViewModelFactoryProtocol { + class SelectValidatorsStartInteractorInputProtocolStub: SelectValidatorsStartInteractorInputProtocol { @@ -25806,126 +25268,27 @@ import UIKit.UIImage - func createAccountViewModel(for wallet: MetaAccountModel) -> SettingsAccountViewModel { - return DefaultValueRegistry.defaultValue(for: (SettingsAccountViewModel).self) - } - - - - func createSectionViewModels(language: Language?, currency: String?, locale: Locale) -> [(SettingsSection, [SettingsCellViewModel])] { - return DefaultValueRegistry.defaultValue(for: ([(SettingsSection, [SettingsCellViewModel])]).self) + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } } - class MockSettingsInteractorInputProtocol: SettingsInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockSelectValidatorsStartInteractorOutputProtocol: SelectValidatorsStartInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SettingsInteractorInputProtocol + typealias MocksType = SelectValidatorsStartInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_SettingsInteractorInputProtocol - typealias Verification = __VerificationProxy_SettingsInteractorInputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: SettingsInteractorInputProtocol? - - func enableDefaultImplementation(_ stub: SettingsInteractorInputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - - - - - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - - } - - - struct __StubbingProxy_SettingsInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_SettingsInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class SettingsInteractorInputProtocolStub: SettingsInteractorInputProtocol { - - - - - - - - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - - - class MockSettingsInteractorOutputProtocol: SettingsInteractorOutputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = SettingsInteractorOutputProtocol - - typealias Stubbing = __StubbingProxy_SettingsInteractorOutputProtocol - typealias Verification = __VerificationProxy_SettingsInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_SelectValidatorsStartInteractorOutputProtocol + typealias Verification = __VerificationProxy_SelectValidatorsStartInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SettingsInteractorOutputProtocol? + private var __defaultImplStub: SelectValidatorsStartInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: SettingsInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsStartInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -25938,51 +25301,36 @@ import UIKit.UIImage - func didReceive(wallet: MetaAccountModel) { - - return cuckoo_manager.call("didReceive(wallet: MetaAccountModel)", - parameters: (wallet), - escapingParameters: (wallet), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(wallet: wallet)) - - } - - - - func didReceiveUserDataProvider(error: Error) { + func didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>) { - return cuckoo_manager.call("didReceiveUserDataProvider(error: Error)", - parameters: (error), - escapingParameters: (error), + return cuckoo_manager.call("didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveUserDataProvider(error: error)) + defaultCall: __defaultImplStub!.didReceiveValidators(result: result)) } - func didReceive(currencyCode: String) { + func didReceiveMaxNominations(result: Result) { - return cuckoo_manager.call("didReceive(currencyCode: String)", - parameters: (currencyCode), - escapingParameters: (currencyCode), + return cuckoo_manager.call("didReceiveMaxNominations(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(currencyCode: currencyCode)) + defaultCall: __defaultImplStub!.didReceiveMaxNominations(result: result)) } - struct __StubbingProxy_SettingsInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsStartInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -25990,24 +25338,19 @@ import UIKit.UIImage } - func didReceive(wallet: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(MetaAccountModel)> where M1.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsInteractorOutputProtocol.self, method: "didReceive(wallet: MetaAccountModel)", parameterMatchers: matchers)) - } - - func didReceiveUserDataProvider(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsInteractorOutputProtocol.self, method: "didReceiveUserDataProvider(error: Error)", parameterMatchers: matchers)) + func didReceiveValidators(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[ElectedValidatorInfo], Error>)> where M1.MatchedType == Result<[ElectedValidatorInfo], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[ElectedValidatorInfo], Error>)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartInteractorOutputProtocol.self, method: "didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>)", parameterMatchers: matchers)) } - func didReceive(currencyCode: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: currencyCode) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsInteractorOutputProtocol.self, method: "didReceive(currencyCode: String)", parameterMatchers: matchers)) + func didReceiveMaxNominations(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartInteractorOutputProtocol.self, method: "didReceiveMaxNominations(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_SettingsInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsStartInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -26022,27 +25365,21 @@ import UIKit.UIImage @discardableResult - func didReceive(wallet: M1) -> Cuckoo.__DoNotUse<(MetaAccountModel), Void> where M1.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: wallet) { $0 }] - return cuckoo_manager.verify("didReceive(wallet: MetaAccountModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveUserDataProvider(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return cuckoo_manager.verify("didReceiveUserDataProvider(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveValidators(result: M1) -> Cuckoo.__DoNotUse<(Result<[ElectedValidatorInfo], Error>), Void> where M1.MatchedType == Result<[ElectedValidatorInfo], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[ElectedValidatorInfo], Error>)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(currencyCode: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: currencyCode) { $0 }] - return cuckoo_manager.verify("didReceive(currencyCode: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveMaxNominations(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMaxNominations(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SettingsInteractorOutputProtocolStub: SettingsInteractorOutputProtocol { + class SelectValidatorsStartInteractorOutputProtocolStub: SelectValidatorsStartInteractorOutputProtocol { @@ -26050,19 +25387,13 @@ import UIKit.UIImage - func didReceive(wallet: MetaAccountModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveUserDataProvider(error: Error) { + func didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(currencyCode: String) { + func didReceiveMaxNominations(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -26070,19 +25401,19 @@ import UIKit.UIImage - class MockSettingsWireframeProtocol: SettingsWireframeProtocol, Cuckoo.ProtocolMock { + class MockSelectValidatorsStartWireframeProtocol: SelectValidatorsStartWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SettingsWireframeProtocol + typealias MocksType = SelectValidatorsStartWireframeProtocol - typealias Stubbing = __StubbingProxy_SettingsWireframeProtocol - typealias Verification = __VerificationProxy_SettingsWireframeProtocol + typealias Stubbing = __StubbingProxy_SelectValidatorsStartWireframeProtocol + typealias Verification = __VerificationProxy_SelectValidatorsStartWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SettingsWireframeProtocol? + private var __defaultImplStub: SelectValidatorsStartWireframeProtocol? - func enableDefaultImplementation(_ stub: SettingsWireframeProtocol) { + func enableDefaultImplementation(_ stub: SelectValidatorsStartWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -26095,76 +25426,46 @@ import UIKit.UIImage - func showAccountDetails(for walletId: String, from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("showAccountDetails(for: String, from: ControllerBackedProtocol?)", - parameters: (walletId, view), - escapingParameters: (walletId, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showAccountDetails(for: walletId, from: view)) - - } - - - - func showAccountSelection(from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("showAccountSelection(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showAccountSelection(from: view)) - - } - - - - func showLanguageSelection(from view: ControllerBackedProtocol?) { + func proceedToCustomList(from view: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams) { - return cuckoo_manager.call("showLanguageSelection(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("proceedToCustomList(from: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams)", + parameters: (view, selectionValidatorGroups, selectedValidatorList, validatorsSelectionParams), + escapingParameters: (view, selectionValidatorGroups, selectedValidatorList, validatorsSelectionParams), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showLanguageSelection(from: view)) + defaultCall: __defaultImplStub!.proceedToCustomList(from: view, selectionValidatorGroups: selectionValidatorGroups, selectedValidatorList: selectedValidatorList, validatorsSelectionParams: validatorsSelectionParams)) } - func showPincodeChange(from view: ControllerBackedProtocol?) { + func proceedToRecommendedList(from view: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int) { - return cuckoo_manager.call("showPincodeChange(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("proceedToRecommendedList(from: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int)", + parameters: (view, validatorList, maxTargets), + escapingParameters: (view, validatorList, maxTargets), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showPincodeChange(from: view)) + defaultCall: __defaultImplStub!.proceedToRecommendedList(from: view, validatorList: validatorList, maxTargets: maxTargets)) } - func showCurrencies(from view: ControllerBackedProtocol?) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - return cuckoo_manager.call("showCurrencies(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", + parameters: (url, view, style), + escapingParameters: (url, view, style), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showCurrencies(from: view)) + defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) } @@ -26198,38 +25499,8 @@ import UIKit.UIImage } - - - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - - return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", - parameters: (url, view, style), - escapingParameters: (url, view, style), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) - - } - - - - func presentSuccessNotification(_ title: String, from view: ControllerBackedProtocol?, completion closure: (() -> Void)?) { - - return cuckoo_manager.call("presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", - parameters: (title, view, closure), - escapingParameters: (title, view, closure), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.presentSuccessNotification(title, from: view, completion: closure)) - - } - - struct __StubbingProxy_SettingsWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectValidatorsStartWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -26237,54 +25508,34 @@ import UIKit.UIImage } - func showAccountDetails(for walletId: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(String, ControllerBackedProtocol?)> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?)>] = [wrap(matchable: walletId) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showAccountDetails(for: String, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func showAccountSelection(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showAccountSelection(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func showLanguageSelection(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showLanguageSelection(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func proceedToCustomList(from view: M1, selectionValidatorGroups: M2, selectedValidatorList: M3, validatorsSelectionParams: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, SelectionValidatorGroups, SharedList, ValidatorsSelectionParams)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == SelectionValidatorGroups, M3.MatchedType == SharedList, M4.MatchedType == ValidatorsSelectionParams { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, SelectionValidatorGroups, SharedList, ValidatorsSelectionParams)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: selectionValidatorGroups) { $0.1 }, wrap(matchable: selectedValidatorList) { $0.2 }, wrap(matchable: validatorsSelectionParams) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "proceedToCustomList(from: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams)", parameterMatchers: matchers)) } - func showPincodeChange(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showPincodeChange(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func proceedToRecommendedList(from view: M1, validatorList: M2, maxTargets: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectValidatorsStartViewProtocol?, [SelectedValidatorInfo], Int)> where M1.OptionalMatchedType == SelectValidatorsStartViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsStartViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: validatorList) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "proceedToRecommendedList(from: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int)", parameterMatchers: matchers)) } - func showCurrencies(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showCurrencies(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) - } - - func presentSuccessNotification(_ title: M1, from view: M2, completion closure: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(String, ControllerBackedProtocol?, (() -> Void)?)> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == (() -> Void) { - let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?, (() -> Void)?)>] = [wrap(matchable: title) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: closure) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSettingsWireframeProtocol.self, method: "presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_SettingsWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectValidatorsStartWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -26299,33 +25550,21 @@ import UIKit.UIImage @discardableResult - func showAccountDetails(for walletId: M1, from view: M2) -> Cuckoo.__DoNotUse<(String, ControllerBackedProtocol?), Void> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?)>] = [wrap(matchable: walletId) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("showAccountDetails(for: String, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showAccountSelection(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showAccountSelection(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showLanguageSelection(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showLanguageSelection(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceedToCustomList(from view: M1, selectionValidatorGroups: M2, selectedValidatorList: M3, validatorsSelectionParams: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, SelectionValidatorGroups, SharedList, ValidatorsSelectionParams), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == SelectionValidatorGroups, M3.MatchedType == SharedList, M4.MatchedType == ValidatorsSelectionParams { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, SelectionValidatorGroups, SharedList, ValidatorsSelectionParams)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: selectionValidatorGroups) { $0.1 }, wrap(matchable: selectedValidatorList) { $0.2 }, wrap(matchable: validatorsSelectionParams) { $0.3 }] + return cuckoo_manager.verify("proceedToCustomList(from: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showPincodeChange(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showPincodeChange(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceedToRecommendedList(from view: M1, validatorList: M2, maxTargets: M3) -> Cuckoo.__DoNotUse<(SelectValidatorsStartViewProtocol?, [SelectedValidatorInfo], Int), Void> where M1.OptionalMatchedType == SelectValidatorsStartViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsStartViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: validatorList) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] + return cuckoo_manager.verify("proceedToRecommendedList(from: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showCurrencies(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showCurrencies(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -26340,22 +25579,10 @@ import UIKit.UIImage return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - @discardableResult - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func presentSuccessNotification(_ title: M1, from view: M2, completion closure: M3) -> Cuckoo.__DoNotUse<(String, ControllerBackedProtocol?, (() -> Void)?), Void> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == (() -> Void) { - let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?, (() -> Void)?)>] = [wrap(matchable: title) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: closure) { $0.2 }] - return cuckoo_manager.verify("presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } - class SettingsWireframeProtocolStub: SettingsWireframeProtocol { + class SelectValidatorsStartWireframeProtocolStub: SelectValidatorsStartWireframeProtocol { @@ -26363,31 +25590,19 @@ import UIKit.UIImage - func showAccountDetails(for walletId: String, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showAccountSelection(from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showLanguageSelection(from view: ControllerBackedProtocol?) { + func proceedToCustomList(from view: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showPincodeChange(from view: ControllerBackedProtocol?) { + func proceedToRecommendedList(from view: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showCurrencies(from view: ControllerBackedProtocol?) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -26403,18 +25618,6 @@ import UIKit.UIImage return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func presentSuccessNotification(_ title: String, from view: ControllerBackedProtocol?, completion closure: (() -> Void)?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - } @@ -26424,19 +25627,19 @@ import Cuckoo import SoraFoundation - class MockAnalyticsRewardDetailsViewProtocol: AnalyticsRewardDetailsViewProtocol, Cuckoo.ProtocolMock { + class MockSelectedValidatorListViewProtocol: SelectedValidatorListViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = AnalyticsRewardDetailsViewProtocol + typealias MocksType = SelectedValidatorListViewProtocol - typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsViewProtocol - typealias Verification = __VerificationProxy_AnalyticsRewardDetailsViewProtocol + typealias Stubbing = __StubbingProxy_SelectedValidatorListViewProtocol + typealias Verification = __VerificationProxy_SelectedValidatorListViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: AnalyticsRewardDetailsViewProtocol? + private var __defaultImplStub: SelectedValidatorListViewProtocol? - func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsViewProtocol) { + func enableDefaultImplementation(_ stub: SelectedValidatorListViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -26501,16 +25704,31 @@ import SoraFoundation - func bind(viewModel: LocalizableResource) { + func didReload(_ viewModel: SelectedValidatorListViewModel) { - return cuckoo_manager.call("bind(viewModel: LocalizableResource)", + return cuckoo_manager.call("didReload(_: SelectedValidatorListViewModel)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.bind(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReload(viewModel)) + + } + + + + func didChangeViewModel(_ viewModel: SelectedValidatorListViewModel, byRemovingItemAt index: Int) { + + return cuckoo_manager.call("didChangeViewModel(_: SelectedValidatorListViewModel, byRemovingItemAt: Int)", + parameters: (viewModel, index), + escapingParameters: (viewModel, index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didChangeViewModel(viewModel, byRemovingItemAt: index)) } @@ -26530,7 +25748,7 @@ import SoraFoundation } - struct __StubbingProxy_AnalyticsRewardDetailsViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectedValidatorListViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -26538,34 +25756,39 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - func bind(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsViewProtocol.self, method: "bind(viewModel: LocalizableResource)", parameterMatchers: matchers)) + func didReload(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorListViewModel)> where M1.MatchedType == SelectedValidatorListViewModel { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListViewProtocol.self, method: "didReload(_: SelectedValidatorListViewModel)", parameterMatchers: matchers)) + } + + func didChangeViewModel(_ viewModel: M1, byRemovingItemAt index: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorListViewModel, Int)> where M1.MatchedType == SelectedValidatorListViewModel, M2.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewModel, Int)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: index) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListViewProtocol.self, method: "didChangeViewModel(_: SelectedValidatorListViewModel, byRemovingItemAt: Int)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_AnalyticsRewardDetailsViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectedValidatorListViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -26595,9 +25818,15 @@ import SoraFoundation @discardableResult - func bind(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("bind(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReload(_ viewModel: M1) -> Cuckoo.__DoNotUse<(SelectedValidatorListViewModel), Void> where M1.MatchedType == SelectedValidatorListViewModel { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReload(_: SelectedValidatorListViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didChangeViewModel(_ viewModel: M1, byRemovingItemAt index: M2) -> Cuckoo.__DoNotUse<(SelectedValidatorListViewModel, Int), Void> where M1.MatchedType == SelectedValidatorListViewModel, M2.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewModel, Int)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: index) { $0.1 }] + return cuckoo_manager.verify("didChangeViewModel(_: SelectedValidatorListViewModel, byRemovingItemAt: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -26609,7 +25838,7 @@ import SoraFoundation } } - class AnalyticsRewardDetailsViewProtocolStub: AnalyticsRewardDetailsViewProtocol { + class SelectedValidatorListViewProtocolStub: SelectedValidatorListViewProtocol { @@ -26646,7 +25875,13 @@ import SoraFoundation - func bind(viewModel: LocalizableResource) { + func didReload(_ viewModel: SelectedValidatorListViewModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didChangeViewModel(_ viewModel: SelectedValidatorListViewModel, byRemovingItemAt index: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -26660,19 +25895,19 @@ import SoraFoundation - class MockAnalyticsRewardDetailsPresenterProtocol: AnalyticsRewardDetailsPresenterProtocol, Cuckoo.ProtocolMock { + class MockSelectedValidatorListDelegate: SelectedValidatorListDelegate, Cuckoo.ProtocolMock { - typealias MocksType = AnalyticsRewardDetailsPresenterProtocol + typealias MocksType = SelectedValidatorListDelegate - typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsPresenterProtocol - typealias Verification = __VerificationProxy_AnalyticsRewardDetailsPresenterProtocol + typealias Stubbing = __StubbingProxy_SelectedValidatorListDelegate + typealias Verification = __VerificationProxy_SelectedValidatorListDelegate let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: AnalyticsRewardDetailsPresenterProtocol? + private var __defaultImplStub: SelectedValidatorListDelegate? - func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsPresenterProtocol) { + func enableDefaultImplementation(_ stub: SelectedValidatorListDelegate) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -26685,36 +25920,21 @@ import SoraFoundation - func setup() { + func didRemove(_ validator: SelectedValidatorInfo) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didRemove(_: SelectedValidatorInfo)", + parameters: (validator), + escapingParameters: (validator), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) - - } - - - - func handleEventIdAction() { - - return cuckoo_manager.call("handleEventIdAction()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.handleEventIdAction()) + defaultCall: __defaultImplStub!.didRemove(validator)) } - struct __StubbingProxy_AnalyticsRewardDetailsPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectedValidatorListDelegate: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -26722,19 +25942,14 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func handleEventIdAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsPresenterProtocol.self, method: "handleEventIdAction()", parameterMatchers: matchers)) + func didRemove(_ validator: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorInfo)> where M1.MatchedType == SelectedValidatorInfo { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo)>] = [wrap(matchable: validator) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListDelegate.self, method: "didRemove(_: SelectedValidatorInfo)", parameterMatchers: matchers)) } } - struct __VerificationProxy_AnalyticsRewardDetailsPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectedValidatorListDelegate: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -26749,21 +25964,15 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func handleEventIdAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handleEventIdAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didRemove(_ validator: M1) -> Cuckoo.__DoNotUse<(SelectedValidatorInfo), Void> where M1.MatchedType == SelectedValidatorInfo { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo)>] = [wrap(matchable: validator) { $0 }] + return cuckoo_manager.verify("didRemove(_: SelectedValidatorInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class AnalyticsRewardDetailsPresenterProtocolStub: AnalyticsRewardDetailsPresenterProtocol { + class SelectedValidatorListDelegateStub: SelectedValidatorListDelegate { @@ -26771,13 +25980,7 @@ import SoraFoundation - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func handleEventIdAction() { + func didRemove(_ validator: SelectedValidatorInfo) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -26785,80 +25988,19 @@ import SoraFoundation - class MockAnalyticsRewardDetailsInteractorInputProtocol: AnalyticsRewardDetailsInteractorInputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = AnalyticsRewardDetailsInteractorInputProtocol - - typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsInteractorInputProtocol - typealias Verification = __VerificationProxy_AnalyticsRewardDetailsInteractorInputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: AnalyticsRewardDetailsInteractorInputProtocol? - - func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsInteractorInputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - - - - struct __StubbingProxy_AnalyticsRewardDetailsInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - } - - struct __VerificationProxy_AnalyticsRewardDetailsInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - } -} - - class AnalyticsRewardDetailsInteractorInputProtocolStub: AnalyticsRewardDetailsInteractorInputProtocol { - - - - - -} - - - - class MockAnalyticsRewardDetailsInteractorOutputProtocol: AnalyticsRewardDetailsInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockSelectedValidatorListPresenterProtocol: SelectedValidatorListPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = AnalyticsRewardDetailsInteractorOutputProtocol + typealias MocksType = SelectedValidatorListPresenterProtocol - typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsInteractorOutputProtocol - typealias Verification = __VerificationProxy_AnalyticsRewardDetailsInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_SelectedValidatorListPresenterProtocol + typealias Verification = __VerificationProxy_SelectedValidatorListPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: AnalyticsRewardDetailsInteractorOutputProtocol? + private var __defaultImplStub: SelectedValidatorListPresenterProtocol? - func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: SelectedValidatorListPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -26869,129 +26011,83 @@ import SoraFoundation - - struct __StubbingProxy_AnalyticsRewardDetailsInteractorOutputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - } - - struct __VerificationProxy_AnalyticsRewardDetailsInteractorOutputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - } -} - - class AnalyticsRewardDetailsInteractorOutputProtocolStub: AnalyticsRewardDetailsInteractorOutputProtocol { - - - - - -} - - - - class MockAnalyticsRewardDetailsWireframeProtocol: AnalyticsRewardDetailsWireframeProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = AnalyticsRewardDetailsWireframeProtocol - typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsWireframeProtocol - typealias Verification = __VerificationProxy_AnalyticsRewardDetailsWireframeProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: AnalyticsRewardDetailsWireframeProtocol? - - func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsWireframeProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func setup() { + + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.setup()) + } - - - - - - - func presentSuccessNotification(_ title: String, from view: ControllerBackedProtocol?, completion closure: (() -> Void)?) { + func didSelectValidator(at index: Int) { - return cuckoo_manager.call("presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", - parameters: (title, view, closure), - escapingParameters: (title, view, closure), + return cuckoo_manager.call("didSelectValidator(at: Int)", + parameters: (index), + escapingParameters: (index), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentSuccessNotification(title, from: view, completion: closure)) + defaultCall: __defaultImplStub!.didSelectValidator(at: index)) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func removeItem(at index: Int) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("removeItem(at: Int)", + parameters: (index), + escapingParameters: (index), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.removeItem(at: index)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func proceed() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("proceed()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.proceed()) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func dismiss() { - return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", - parameters: (url, view, style), - escapingParameters: (url, view, style), + return cuckoo_manager.call("dismiss()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) + defaultCall: __defaultImplStub!.dismiss()) } - struct __StubbingProxy_AnalyticsRewardDetailsWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectedValidatorListPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -26999,29 +26095,34 @@ import SoraFoundation } - func presentSuccessNotification(_ title: M1, from view: M2, completion closure: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(String, ControllerBackedProtocol?, (() -> Void)?)> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == (() -> Void) { - let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?, (() -> Void)?)>] = [wrap(matchable: title) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: closure) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsWireframeProtocol.self, method: "presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didSelectValidator(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "didSelectValidator(at: Int)", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func removeItem(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "removeItem(at: Int)", parameterMatchers: matchers)) } - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + } + + func dismiss() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "dismiss()", parameterMatchers: matchers)) } } - struct __VerificationProxy_AnalyticsRewardDetailsWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectedValidatorListPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -27036,33 +26137,39 @@ import SoraFoundation @discardableResult - func presentSuccessNotification(_ title: M1, from view: M2, completion closure: M3) -> Cuckoo.__DoNotUse<(String, ControllerBackedProtocol?, (() -> Void)?), Void> where M1.MatchedType == String, M2.OptionalMatchedType == ControllerBackedProtocol, M3.OptionalMatchedType == (() -> Void) { - let matchers: [Cuckoo.ParameterMatcher<(String, ControllerBackedProtocol?, (() -> Void)?)>] = [wrap(matchable: title) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: closure) { $0.2 }] - return cuckoo_manager.verify("presentSuccessNotification(_: String, from: ControllerBackedProtocol?, completion: (() -> Void)?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didSelectValidator(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("didSelectValidator(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func removeItem(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("removeItem(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceed() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func dismiss() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("dismiss()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class AnalyticsRewardDetailsWireframeProtocolStub: AnalyticsRewardDetailsWireframeProtocol { + class SelectedValidatorListPresenterProtocolStub: SelectedValidatorListPresenterProtocol { @@ -27070,25 +26177,31 @@ import SoraFoundation - func presentSuccessNotification(_ title: String, from view: ControllerBackedProtocol?, completion closure: (() -> Void)?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func didSelectValidator(at index: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func removeItem(at index: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func proceed() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func dismiss() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -27096,19 +26209,19 @@ import SoraFoundation - class MockAnalyticsRewardDetailsViewModelFactoryProtocol: AnalyticsRewardDetailsViewModelFactoryProtocol, Cuckoo.ProtocolMock { + class MockSelectedValidatorListViewModelFactoryProtocol: SelectedValidatorListViewModelFactoryProtocol, Cuckoo.ProtocolMock { - typealias MocksType = AnalyticsRewardDetailsViewModelFactoryProtocol + typealias MocksType = SelectedValidatorListViewModelFactoryProtocol - typealias Stubbing = __StubbingProxy_AnalyticsRewardDetailsViewModelFactoryProtocol - typealias Verification = __VerificationProxy_AnalyticsRewardDetailsViewModelFactoryProtocol + typealias Stubbing = __StubbingProxy_SelectedValidatorListViewModelFactoryProtocol + typealias Verification = __VerificationProxy_SelectedValidatorListViewModelFactoryProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: AnalyticsRewardDetailsViewModelFactoryProtocol? + private var __defaultImplStub: SelectedValidatorListViewModelFactoryProtocol? - func enableDefaultImplementation(_ stub: AnalyticsRewardDetailsViewModelFactoryProtocol) { + func enableDefaultImplementation(_ stub: SelectedValidatorListViewModelFactoryProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -27121,21 +26234,21 @@ import SoraFoundation - func createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource { + func createViewModel(from validatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel { - return cuckoo_manager.call("createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource", - parameters: (rewardModel), - escapingParameters: (rewardModel), + return cuckoo_manager.call("createViewModel(from: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel", + parameters: (validatorList, totalValidatorsCount, locale), + escapingParameters: (validatorList, totalValidatorsCount, locale), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.createViweModel(rewardModel: rewardModel)) + defaultCall: __defaultImplStub!.createViewModel(from: validatorList, totalValidatorsCount: totalValidatorsCount, locale: locale)) } - struct __StubbingProxy_AnalyticsRewardDetailsViewModelFactoryProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectedValidatorListViewModelFactoryProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -27143,14 +26256,14 @@ import SoraFoundation } - func createViweModel(rewardModel: M1) -> Cuckoo.ProtocolStubFunction<(AnalyticsRewardDetailsModel), LocalizableResource> where M1.MatchedType == AnalyticsRewardDetailsModel { - let matchers: [Cuckoo.ParameterMatcher<(AnalyticsRewardDetailsModel)>] = [wrap(matchable: rewardModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockAnalyticsRewardDetailsViewModelFactoryProtocol.self, method: "createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource", parameterMatchers: matchers)) + func createViewModel(from validatorList: M1, totalValidatorsCount: M2, locale: M3) -> Cuckoo.ProtocolStubFunction<([SelectedValidatorInfo], Int, Locale), SelectedValidatorListViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == Int, M3.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], Int, Locale)>] = [wrap(matchable: validatorList) { $0.0 }, wrap(matchable: totalValidatorsCount) { $0.1 }, wrap(matchable: locale) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListViewModelFactoryProtocol.self, method: "createViewModel(from: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel", parameterMatchers: matchers)) } } - struct __VerificationProxy_AnalyticsRewardDetailsViewModelFactoryProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectedValidatorListViewModelFactoryProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -27165,15 +26278,15 @@ import SoraFoundation @discardableResult - func createViweModel(rewardModel: M1) -> Cuckoo.__DoNotUse<(AnalyticsRewardDetailsModel), LocalizableResource> where M1.MatchedType == AnalyticsRewardDetailsModel { - let matchers: [Cuckoo.ParameterMatcher<(AnalyticsRewardDetailsModel)>] = [wrap(matchable: rewardModel) { $0 }] - return cuckoo_manager.verify("createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func createViewModel(from validatorList: M1, totalValidatorsCount: M2, locale: M3) -> Cuckoo.__DoNotUse<([SelectedValidatorInfo], Int, Locale), SelectedValidatorListViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == Int, M3.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], Int, Locale)>] = [wrap(matchable: validatorList) { $0.0 }, wrap(matchable: totalValidatorsCount) { $0.1 }, wrap(matchable: locale) { $0.2 }] + return cuckoo_manager.verify("createViewModel(from: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class AnalyticsRewardDetailsViewModelFactoryProtocolStub: AnalyticsRewardDetailsViewModelFactoryProtocol { + class SelectedValidatorListViewModelFactoryProtocolStub: SelectedValidatorListViewModelFactoryProtocol { @@ -27181,141 +26294,114 @@ import SoraFoundation - func createViweModel(rewardModel: AnalyticsRewardDetailsModel) -> LocalizableResource { - return DefaultValueRegistry.defaultValue(for: (LocalizableResource).self) + func createViewModel(from validatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel { + return DefaultValueRegistry.defaultValue(for: (SelectedValidatorListViewModel).self) } } -import Cuckoo -@testable import novawallet - -import SoraFoundation - - class MockControllerAccountViewProtocol: ControllerAccountViewProtocol, Cuckoo.ProtocolMock { + class MockSelectedValidatorListWireframeProtocol: SelectedValidatorListWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ControllerAccountViewProtocol + typealias MocksType = SelectedValidatorListWireframeProtocol - typealias Stubbing = __StubbingProxy_ControllerAccountViewProtocol - typealias Verification = __VerificationProxy_ControllerAccountViewProtocol + typealias Stubbing = __StubbingProxy_SelectedValidatorListWireframeProtocol + typealias Verification = __VerificationProxy_SelectedValidatorListWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ControllerAccountViewProtocol? + private var __defaultImplStub: SelectedValidatorListWireframeProtocol? - func enableDefaultImplementation(_ stub: ControllerAccountViewProtocol) { + func enableDefaultImplementation(_ stub: SelectedValidatorListWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } + - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } + func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", + parameters: (validatorInfo, view), + escapingParameters: (validatorInfo, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) } - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } + func proceed(from view: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int) { - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } + return cuckoo_manager.call("proceed(from: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", + parameters: (view, targets, maxTargets), + escapingParameters: (view, targets, maxTargets), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.proceed(from: view, targets: targets, maxTargets: maxTargets)) } - - - - - func reload(with viewModel: ControllerAccountViewModel) { + func dismiss(_ view: ControllerBackedProtocol?) { - return cuckoo_manager.call("reload(with: ControllerAccountViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("dismiss(_: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload(with: viewModel)) + defaultCall: __defaultImplStub!.dismiss(view)) } - func didCompleteControllerSelection() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("didCompleteControllerSelection()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didCompleteControllerSelection()) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - public func applyLocalization() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_ControllerAccountViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_SelectedValidatorListWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -27323,39 +26409,34 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoProtocol, ControllerBackedProtocol?)> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") + func proceed(from view: M1, targets: M2, maxTargets: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)> where M1.OptionalMatchedType == SelectedValidatorListViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: targets) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "proceed(from: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", parameterMatchers: matchers)) } - - func reload(with viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerAccountViewModel)> where M1.MatchedType == ControllerAccountViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ControllerAccountViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountViewProtocol.self, method: "reload(with: ControllerAccountViewModel)", parameterMatchers: matchers)) + func dismiss(_ view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "dismiss(_: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func didCompleteControllerSelection() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountViewProtocol.self, method: "didCompleteControllerSelection()", parameterMatchers: matchers)) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ControllerAccountViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_SelectedValidatorListWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -27367,74 +26448,42 @@ import SoraFoundation } + - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(ValidatorInfoProtocol, ControllerBackedProtocol?), Void> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func proceed(from view: M1, targets: M2, maxTargets: M3) -> Cuckoo.__DoNotUse<(SelectedValidatorListViewProtocol?, [SelectedValidatorInfo], Int), Void> where M1.OptionalMatchedType == SelectedValidatorListViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: targets) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] + return cuckoo_manager.verify("proceed(from: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - @discardableResult - func reload(with viewModel: M1) -> Cuckoo.__DoNotUse<(ControllerAccountViewModel), Void> where M1.MatchedType == ControllerAccountViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ControllerAccountViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("reload(with: ControllerAccountViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func dismiss(_ view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("dismiss(_: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didCompleteControllerSelection() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didCompleteControllerSelection()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ControllerAccountViewProtocolStub: ControllerAccountViewProtocol { - - - - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - - - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - - } + class SelectedValidatorListWireframeProtocolStub: SelectedValidatorListWireframeProtocol { @@ -27442,219 +26491,153 @@ import SoraFoundation - func reload(with viewModel: ControllerAccountViewModel) { + func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didCompleteControllerSelection() { + func proceed(from view: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func dismiss(_ view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockControllerAccountViewModelFactoryProtocol: ControllerAccountViewModelFactoryProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ControllerAccountViewModelFactoryProtocol - typealias Stubbing = __StubbingProxy_ControllerAccountViewModelFactoryProtocol - typealias Verification = __VerificationProxy_ControllerAccountViewModelFactoryProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ControllerAccountViewModelFactoryProtocol? - - func enableDefaultImplementation(_ stub: ControllerAccountViewModelFactoryProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - - - - - func createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel { - - return cuckoo_manager.call("createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel", - parameters: (stashItem, stashAccountItem, chosenAccountItem), - escapingParameters: (stashItem, stashAccountItem, chosenAccountItem), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.createViewModel(stashItem: stashItem, stashAccountItem: stashAccountItem, chosenAccountItem: chosenAccountItem)) - + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - struct __StubbingProxy_ControllerAccountViewModelFactoryProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func createViewModel(stashItem: M1, stashAccountItem: M2, chosenAccountItem: M3) -> Cuckoo.ProtocolStubFunction<(StashItem, MetaChainAccountResponse?, MetaChainAccountResponse?), ControllerAccountViewModel> where M1.MatchedType == StashItem, M2.OptionalMatchedType == MetaChainAccountResponse, M3.OptionalMatchedType == MetaChainAccountResponse { - let matchers: [Cuckoo.ParameterMatcher<(StashItem, MetaChainAccountResponse?, MetaChainAccountResponse?)>] = [wrap(matchable: stashItem) { $0.0 }, wrap(matchable: stashAccountItem) { $0.1 }, wrap(matchable: chosenAccountItem) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountViewModelFactoryProtocol.self, method: "createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ControllerAccountViewModelFactoryProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func createViewModel(stashItem: M1, stashAccountItem: M2, chosenAccountItem: M3) -> Cuckoo.__DoNotUse<(StashItem, MetaChainAccountResponse?, MetaChainAccountResponse?), ControllerAccountViewModel> where M1.MatchedType == StashItem, M2.OptionalMatchedType == MetaChainAccountResponse, M3.OptionalMatchedType == MetaChainAccountResponse { - let matchers: [Cuckoo.ParameterMatcher<(StashItem, MetaChainAccountResponse?, MetaChainAccountResponse?)>] = [wrap(matchable: stashItem) { $0.0 }, wrap(matchable: stashAccountItem) { $0.1 }, wrap(matchable: chosenAccountItem) { $0.2 }] - return cuckoo_manager.verify("createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } } - class ControllerAccountViewModelFactoryProtocolStub: ControllerAccountViewModelFactoryProtocol { - - - - - - - func createViewModel(stashItem: StashItem, stashAccountItem: MetaChainAccountResponse?, chosenAccountItem: MetaChainAccountResponse?) -> ControllerAccountViewModel { - return DefaultValueRegistry.defaultValue(for: (ControllerAccountViewModel).self) - } - -} +import Cuckoo +@testable import novawallet +import Foundation +import SoraFoundation - class MockControllerAccountPresenterProtocol: ControllerAccountPresenterProtocol, Cuckoo.ProtocolMock { + class MockValidatorStakeInfoProtocol: ValidatorStakeInfoProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ControllerAccountPresenterProtocol + typealias MocksType = ValidatorStakeInfoProtocol - typealias Stubbing = __StubbingProxy_ControllerAccountPresenterProtocol - typealias Verification = __VerificationProxy_ControllerAccountPresenterProtocol + typealias Stubbing = __StubbingProxy_ValidatorStakeInfoProtocol + typealias Verification = __VerificationProxy_ValidatorStakeInfoProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ControllerAccountPresenterProtocol? + private var __defaultImplStub: ValidatorStakeInfoProtocol? - func enableDefaultImplementation(_ stub: ControllerAccountPresenterProtocol) { + func enableDefaultImplementation(_ stub: ValidatorStakeInfoProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - + + var nominators: [NominatorInfo] { + get { + return cuckoo_manager.getter("nominators", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.nominators) + } + + } - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) + var totalStake: Decimal { + get { + return cuckoo_manager.getter("totalStake", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.totalStake) + } } - func handleStashAction() { - - return cuckoo_manager.call("handleStashAction()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.handleStashAction()) + var ownStake: Decimal { + get { + return cuckoo_manager.getter("ownStake", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.ownStake) + } } - func handleControllerAction() { - - return cuckoo_manager.call("handleControllerAction()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.handleControllerAction()) + var stakeReturn: Decimal { + get { + return cuckoo_manager.getter("stakeReturn", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.stakeReturn) + } } - func selectLearnMore() { - - return cuckoo_manager.call("selectLearnMore()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.selectLearnMore()) + var maxNominatorsRewarded: UInt32 { + get { + return cuckoo_manager.getter("maxNominatorsRewarded", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.maxNominatorsRewarded) + } } - func proceed() { - - return cuckoo_manager.call("proceed()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.proceed()) + var oversubscribed: Bool { + get { + return cuckoo_manager.getter("oversubscribed", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.oversubscribed) + } } - struct __StubbingProxy_ControllerAccountPresenterProtocol: Cuckoo.StubbingProxy { + + + + + struct __StubbingProxy_ValidatorStakeInfoProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -27662,34 +26645,39 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + var nominators: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "nominators") } - func handleStashAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "handleStashAction()", parameterMatchers: matchers)) + + var totalStake: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "totalStake") } - func handleControllerAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "handleControllerAction()", parameterMatchers: matchers)) + + var ownStake: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "ownStake") } - func selectLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "selectLearnMore()", parameterMatchers: matchers)) + + var stakeReturn: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "stakeReturn") } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + + var maxNominatorsRewarded: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "maxNominatorsRewarded") } + + var oversubscribed: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "oversubscribed") + } + + } - struct __VerificationProxy_ControllerAccountPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorStakeInfoProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -27701,166 +26689,242 @@ import SoraFoundation } - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var nominators: Cuckoo.VerifyReadOnlyProperty<[NominatorInfo]> { + return .init(manager: cuckoo_manager, name: "nominators", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func handleStashAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handleStashAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var totalStake: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "totalStake", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func handleControllerAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handleControllerAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var ownStake: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "ownStake", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func selectLearnMore() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var stakeReturn: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "stakeReturn", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var maxNominatorsRewarded: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "maxNominatorsRewarded", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var oversubscribed: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "oversubscribed", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + } } - class ControllerAccountPresenterProtocolStub: ControllerAccountPresenterProtocol { - - + class ValidatorStakeInfoProtocolStub: ValidatorStakeInfoProtocol { + - + var nominators: [NominatorInfo] { + get { + return DefaultValueRegistry.defaultValue(for: ([NominatorInfo]).self) + } + + } + - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var totalStake: Decimal { + get { + return DefaultValueRegistry.defaultValue(for: (Decimal).self) + } + } + - - func handleStashAction() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var ownStake: Decimal { + get { + return DefaultValueRegistry.defaultValue(for: (Decimal).self) + } + } + - - func handleControllerAction() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var stakeReturn: Decimal { + get { + return DefaultValueRegistry.defaultValue(for: (Decimal).self) + } + } + - - func selectLearnMore() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var maxNominatorsRewarded: UInt32 { + get { + return DefaultValueRegistry.defaultValue(for: (UInt32).self) + } + } + - - func proceed() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var oversubscribed: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + } + + + + } - class MockControllerAccountInteractorInputProtocol: ControllerAccountInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockValidatorInfoProtocol: ValidatorInfoProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ControllerAccountInteractorInputProtocol + typealias MocksType = ValidatorInfoProtocol - typealias Stubbing = __StubbingProxy_ControllerAccountInteractorInputProtocol - typealias Verification = __VerificationProxy_ControllerAccountInteractorInputProtocol + typealias Stubbing = __StubbingProxy_ValidatorInfoProtocol + typealias Verification = __VerificationProxy_ValidatorInfoProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ControllerAccountInteractorInputProtocol? + private var __defaultImplStub: ValidatorInfoProtocol? - func enableDefaultImplementation(_ stub: ControllerAccountInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: ValidatorInfoProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - + var address: String { + get { + return cuckoo_manager.getter("address", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.address) + } + + } - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) + + var identity: AccountIdentity? { + get { + return cuckoo_manager.getter("identity", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.identity) + } } - func estimateFee(for account: ChainAccountResponse) { - - return cuckoo_manager.call("estimateFee(for: ChainAccountResponse)", - parameters: (account), - escapingParameters: (account), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.estimateFee(for: account)) + var stakeInfo: ValidatorStakeInfoProtocol? { + get { + return cuckoo_manager.getter("stakeInfo", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.stakeInfo) + } } - func fetchLedger(controllerAddress: AccountAddress) { - - return cuckoo_manager.call("fetchLedger(controllerAddress: AccountAddress)", - parameters: (controllerAddress), - escapingParameters: (controllerAddress), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.fetchLedger(controllerAddress: controllerAddress)) + var myNomination: ValidatorMyNominationStatus? { + get { + return cuckoo_manager.getter("myNomination", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.myNomination) + } } - func fetchControllerAccountInfo(controllerAddress: AccountAddress) { - - return cuckoo_manager.call("fetchControllerAccountInfo(controllerAddress: AccountAddress)", - parameters: (controllerAddress), - escapingParameters: (controllerAddress), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.fetchControllerAccountInfo(controllerAddress: controllerAddress)) + var totalStake: Decimal { + get { + return cuckoo_manager.getter("totalStake", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.totalStake) + } + + } + + + + var ownStake: Decimal { + get { + return cuckoo_manager.getter("ownStake", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.ownStake) + } + + } + + + + var hasSlashes: Bool { + get { + return cuckoo_manager.getter("hasSlashes", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.hasSlashes) + } + + } + + + + var blocked: Bool { + get { + return cuckoo_manager.getter("blocked", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.blocked) + } } - struct __StubbingProxy_ControllerAccountInteractorInputProtocol: Cuckoo.StubbingProxy { + + + + + struct __StubbingProxy_ValidatorInfoProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -27868,29 +26932,49 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + var address: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "address") } - func estimateFee(for account: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainAccountResponse)> where M1.MatchedType == ChainAccountResponse { - let matchers: [Cuckoo.ParameterMatcher<(ChainAccountResponse)>] = [wrap(matchable: account) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorInputProtocol.self, method: "estimateFee(for: ChainAccountResponse)", parameterMatchers: matchers)) + + var identity: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "identity") } - func fetchLedger(controllerAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: controllerAddress) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorInputProtocol.self, method: "fetchLedger(controllerAddress: AccountAddress)", parameterMatchers: matchers)) + + var stakeInfo: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "stakeInfo") } - func fetchControllerAccountInfo(controllerAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: controllerAddress) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorInputProtocol.self, method: "fetchControllerAccountInfo(controllerAddress: AccountAddress)", parameterMatchers: matchers)) + + var myNomination: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "myNomination") + } + + + var totalStake: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "totalStake") + } + + + var ownStake: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "ownStake") + } + + + var hasSlashes: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "hasSlashes") + } + + + var blocked: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "blocked") } + } - struct __VerificationProxy_ControllerAccountInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorInfoProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -27902,214 +26986,240 @@ import SoraFoundation } - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var address: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "address", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func estimateFee(for account: M1) -> Cuckoo.__DoNotUse<(ChainAccountResponse), Void> where M1.MatchedType == ChainAccountResponse { - let matchers: [Cuckoo.ParameterMatcher<(ChainAccountResponse)>] = [wrap(matchable: account) { $0 }] - return cuckoo_manager.verify("estimateFee(for: ChainAccountResponse)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var identity: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "identity", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func fetchLedger(controllerAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: controllerAddress) { $0 }] - return cuckoo_manager.verify("fetchLedger(controllerAddress: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var stakeInfo: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "stakeInfo", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func fetchControllerAccountInfo(controllerAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: controllerAddress) { $0 }] - return cuckoo_manager.verify("fetchControllerAccountInfo(controllerAddress: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var myNomination: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "myNomination", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var totalStake: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "totalStake", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var ownStake: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "ownStake", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + var hasSlashes: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "hasSlashes", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var blocked: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "blocked", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + } } - class ControllerAccountInteractorInputProtocolStub: ControllerAccountInteractorInputProtocol { - - + class ValidatorInfoProtocolStub: ValidatorInfoProtocol { + - + var address: String { + get { + return DefaultValueRegistry.defaultValue(for: (String).self) + } + + } + - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var identity: AccountIdentity? { + get { + return DefaultValueRegistry.defaultValue(for: (AccountIdentity?).self) + } + } + + + var stakeInfo: ValidatorStakeInfoProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (ValidatorStakeInfoProtocol?).self) + } + + } + - func estimateFee(for account: ChainAccountResponse) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var myNomination: ValidatorMyNominationStatus? { + get { + return DefaultValueRegistry.defaultValue(for: (ValidatorMyNominationStatus?).self) + } + } + + + var totalStake: Decimal { + get { + return DefaultValueRegistry.defaultValue(for: (Decimal).self) + } + + } + - func fetchLedger(controllerAddress: AccountAddress) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var ownStake: Decimal { + get { + return DefaultValueRegistry.defaultValue(for: (Decimal).self) + } + } + + + var hasSlashes: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + - func fetchControllerAccountInfo(controllerAddress: AccountAddress) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var blocked: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + } + + + + } - class MockControllerAccountInteractorOutputProtocol: ControllerAccountInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockValidatorInfoViewProtocol: ValidatorInfoViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ControllerAccountInteractorOutputProtocol + typealias MocksType = ValidatorInfoViewProtocol - typealias Stubbing = __StubbingProxy_ControllerAccountInteractorOutputProtocol - typealias Verification = __VerificationProxy_ControllerAccountInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_ValidatorInfoViewProtocol + typealias Verification = __VerificationProxy_ValidatorInfoViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ControllerAccountInteractorOutputProtocol? + private var __defaultImplStub: ValidatorInfoViewProtocol? - func enableDefaultImplementation(_ stub: ControllerAccountInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: ValidatorInfoViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - - - - - func didReceiveStashItem(result: Result) { - - return cuckoo_manager.call("didReceiveStashItem(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) - - } - - - - func didReceiveStashAccount(result: Result) { - - return cuckoo_manager.call("didReceiveStashAccount(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveStashAccount(result: result)) - - } - - func didReceiveControllerAccount(result: Result) { - - return cuckoo_manager.call("didReceiveControllerAccount(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveControllerAccount(result: result)) + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } } - func didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>) { - - return cuckoo_manager.call("didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAccounts(result: result)) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } - func didReceiveFee(result: Result) { + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } } + - - func didReceiveControllerAccountInfo(result: Result, address: AccountAddress) { - - return cuckoo_manager.call("didReceiveControllerAccountInfo(result: Result, address: AccountAddress)", - parameters: (result, address), - escapingParameters: (result, address), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveControllerAccountInfo(result: result, address: address)) - - } + - func didReceiveAccountInfo(result: Result, address: AccountAddress) { + func didRecieve(state: ValidatorInfoState) { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result, address: AccountAddress)", - parameters: (result, address), - escapingParameters: (result, address), + return cuckoo_manager.call("didRecieve(state: ValidatorInfoState)", + parameters: (state), + escapingParameters: (state), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result, address: address)) + defaultCall: __defaultImplStub!.didRecieve(state: state)) } - func didReceiveStakingLedger(result: Result) { + public func applyLocalization() { - return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_ControllerAccountInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorInfoViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -28117,49 +27227,34 @@ import SoraFoundation } - func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func didReceiveStashAccount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveStashAccount(result: Result)", parameterMatchers: matchers)) - } - func didReceiveControllerAccount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveControllerAccount(result: Result)", parameterMatchers: matchers)) + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func didReceiveAccounts(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[MetaChainAccountResponse], Error>)> where M1.MatchedType == Result<[MetaChainAccountResponse], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[MetaChainAccountResponse], Error>)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", parameterMatchers: matchers)) - } - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func didReceiveControllerAccountInfo(result: M1, address: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Result, AccountAddress)> where M1.MatchedType == Result, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(Result, AccountAddress)>] = [wrap(matchable: result) { $0.0 }, wrap(matchable: address) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveControllerAccountInfo(result: Result, address: AccountAddress)", parameterMatchers: matchers)) - } - func didReceiveAccountInfo(result: M1, address: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Result, AccountAddress)> where M1.MatchedType == Result, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(Result, AccountAddress)>] = [wrap(matchable: result) { $0.0 }, wrap(matchable: address) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result, address: AccountAddress)", parameterMatchers: matchers)) + func didRecieve(state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoState)> where M1.MatchedType == ValidatorInfoState { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoState)>] = [wrap(matchable: state) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoViewProtocol.self, method: "didRecieve(state: ValidatorInfoState)", parameterMatchers: matchers)) } - func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_ControllerAccountInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorInfoViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -28171,130 +27266,102 @@ import SoraFoundation } - - @discardableResult - func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceiveStashAccount(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashAccount(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveControllerAccount(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveControllerAccount(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceiveAccounts(result: M1) -> Cuckoo.__DoNotUse<(Result<[MetaChainAccountResponse], Error>), Void> where M1.MatchedType == Result<[MetaChainAccountResponse], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[MetaChainAccountResponse], Error>)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceiveControllerAccountInfo(result: M1, address: M2) -> Cuckoo.__DoNotUse<(Result, AccountAddress), Void> where M1.MatchedType == Result, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(Result, AccountAddress)>] = [wrap(matchable: result) { $0.0 }, wrap(matchable: address) { $0.1 }] - return cuckoo_manager.verify("didReceiveControllerAccountInfo(result: Result, address: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } + @discardableResult - func didReceiveAccountInfo(result: M1, address: M2) -> Cuckoo.__DoNotUse<(Result, AccountAddress), Void> where M1.MatchedType == Result, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(Result, AccountAddress)>] = [wrap(matchable: result) { $0.0 }, wrap(matchable: address) { $0.1 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result, address: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didRecieve(state: M1) -> Cuckoo.__DoNotUse<(ValidatorInfoState), Void> where M1.MatchedType == ValidatorInfoState { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoState)>] = [wrap(matchable: state) { $0 }] + return cuckoo_manager.verify("didRecieve(state: ValidatorInfoState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ControllerAccountInteractorOutputProtocolStub: ControllerAccountInteractorOutputProtocol { - - + class ValidatorInfoViewProtocolStub: ValidatorInfoViewProtocol { + - + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + - func didReceiveStashItem(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + - - func didReceiveStashAccount(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + } + - - func didReceiveControllerAccount(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>) { + func didRecieve(state: ValidatorInfoState) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveFee(result: Result) { + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockValidatorInfoInteractorInputProtocol: ValidatorInfoInteractorInputProtocol, Cuckoo.ProtocolMock { + typealias MocksType = ValidatorInfoInteractorInputProtocol - func didReceiveControllerAccountInfo(result: Result, address: AccountAddress) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAccountInfo(result: Result, address: AccountAddress) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveStakingLedger(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - - - class MockControllerAccountWireframeProtocol: ControllerAccountWireframeProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ControllerAccountWireframeProtocol - - typealias Stubbing = __StubbingProxy_ControllerAccountWireframeProtocol - typealias Verification = __VerificationProxy_ControllerAccountWireframeProtocol + typealias Stubbing = __StubbingProxy_ValidatorInfoInteractorInputProtocol + typealias Verification = __VerificationProxy_ValidatorInfoInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ControllerAccountWireframeProtocol? + private var __defaultImplStub: ValidatorInfoInteractorInputProtocol? - func enableDefaultImplementation(_ stub: ControllerAccountWireframeProtocol) { + func enableDefaultImplementation(_ stub: ValidatorInfoInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -28307,96 +27374,36 @@ import SoraFoundation - func showConfirmation(from view: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse) { - - return cuckoo_manager.call("showConfirmation(from: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse)", - parameters: (view, controllerAccountItem), - escapingParameters: (view, controllerAccountItem), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showConfirmation(from: view, controllerAccountItem: controllerAccountItem)) - - } - - - - func close(view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("close(view: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.close(view: view)) - - } - - - - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - - return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", - parameters: (url, view, style), - escapingParameters: (url, view, style), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) - - } - - - - func presentAccountSelection(_ accounts: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from view: ControllerBackedProtocol?, context: AnyObject?) { - - return cuckoo_manager.call("presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", - parameters: (accounts, selectedAccountItem, title, delegate, view, context), - escapingParameters: (accounts, selectedAccountItem, title, delegate, view, context), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.presentAccountSelection(accounts, selectedAccountItem: selectedAccountItem, title: title, delegate: delegate, from: view, context: context)) - - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func setup() { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.setup()) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func reload() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("reload()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.reload()) } - struct __StubbingProxy_ControllerAccountWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorInfoInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -28404,39 +27411,19 @@ import SoraFoundation } - func showConfirmation(from view: M1, controllerAccountItem: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, MetaChainAccountResponse)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaChainAccountResponse { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaChainAccountResponse)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: controllerAccountItem) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "showConfirmation(from: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse)", parameterMatchers: matchers)) - } - - func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "close(view: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) - } - - func presentAccountSelection(_ accounts: M1, selectedAccountItem: M2, title: M3, delegate: M4, from view: M5, context: M6) -> Cuckoo.ProtocolStubNoReturnFunction<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)> where M1.MatchedType == [MetaChainAccountResponse], M2.OptionalMatchedType == MetaChainAccountResponse, M3.MatchedType == LocalizableResource, M4.MatchedType == ModalPickerViewControllerDelegate, M5.OptionalMatchedType == ControllerBackedProtocol, M6.OptionalMatchedType == AnyObject { - let matchers: [Cuckoo.ParameterMatcher<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)>] = [wrap(matchable: accounts) { $0.0 }, wrap(matchable: selectedAccountItem) { $0.1 }, wrap(matchable: title) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: view) { $0.4 }, wrap(matchable: context) { $0.5 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", parameterMatchers: matchers)) - } - - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockControllerAccountWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorInputProtocol.self, method: "reload()", parameterMatchers: matchers)) } } - struct __VerificationProxy_ControllerAccountWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorInfoInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -28451,45 +27438,21 @@ import SoraFoundation @discardableResult - func showConfirmation(from view: M1, controllerAccountItem: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, MetaChainAccountResponse), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaChainAccountResponse { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaChainAccountResponse)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: controllerAccountItem) { $0.1 }] - return cuckoo_manager.verify("showConfirmation(from: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func close(view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(view: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func presentAccountSelection(_ accounts: M1, selectedAccountItem: M2, title: M3, delegate: M4, from view: M5, context: M6) -> Cuckoo.__DoNotUse<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?), Void> where M1.MatchedType == [MetaChainAccountResponse], M2.OptionalMatchedType == MetaChainAccountResponse, M3.MatchedType == LocalizableResource, M4.MatchedType == ModalPickerViewControllerDelegate, M5.OptionalMatchedType == ControllerBackedProtocol, M6.OptionalMatchedType == AnyObject { - let matchers: [Cuckoo.ParameterMatcher<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)>] = [wrap(matchable: accounts) { $0.0 }, wrap(matchable: selectedAccountItem) { $0.1 }, wrap(matchable: title) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: view) { $0.4 }, wrap(matchable: context) { $0.5 }] - return cuckoo_manager.verify("presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ControllerAccountWireframeProtocolStub: ControllerAccountWireframeProtocol { + class ValidatorInfoInteractorInputProtocolStub: ValidatorInfoInteractorInputProtocol { @@ -28497,64 +27460,33 @@ import SoraFoundation - func showConfirmation(from view: ControllerBackedProtocol?, controllerAccountItem: MetaChainAccountResponse) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func close(view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func presentAccountSelection(_ accounts: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from view: ControllerBackedProtocol?, context: AnyObject?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func reload() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import BigInt -import Foundation -import RobinHood - - class MockNetworkStakingInfoOperationFactoryProtocol: NetworkStakingInfoOperationFactoryProtocol, Cuckoo.ProtocolMock { + class MockValidatorInfoInteractorOutputProtocol: ValidatorInfoInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = NetworkStakingInfoOperationFactoryProtocol + typealias MocksType = ValidatorInfoInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_NetworkStakingInfoOperationFactoryProtocol - typealias Verification = __VerificationProxy_NetworkStakingInfoOperationFactoryProtocol + typealias Stubbing = __StubbingProxy_ValidatorInfoInteractorOutputProtocol + typealias Verification = __VerificationProxy_ValidatorInfoInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: NetworkStakingInfoOperationFactoryProtocol? + private var __defaultImplStub: ValidatorInfoInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: NetworkStakingInfoOperationFactoryProtocol) { + func enableDefaultImplementation(_ stub: ValidatorInfoInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -28567,21 +27499,51 @@ import RobinHood - func networkStakingOperation(for eraValidatorService: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("networkStakingOperation(for: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper", - parameters: (eraValidatorService, runtimeService), - escapingParameters: (eraValidatorService, runtimeService), + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.networkStakingOperation(for: eraValidatorService, runtimeService: runtimeService)) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + + } + + + + func didStartLoadingValidatorInfo() { + + return cuckoo_manager.call("didStartLoadingValidatorInfo()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStartLoadingValidatorInfo()) + + } + + + + func didReceiveValidatorInfo(result: Result) { + + return cuckoo_manager.call("didReceiveValidatorInfo(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveValidatorInfo(result: result)) } - struct __StubbingProxy_NetworkStakingInfoOperationFactoryProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorInfoInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -28589,14 +27551,24 @@ import RobinHood } - func networkStakingOperation(for eraValidatorService: M1, runtimeService: M2) -> Cuckoo.ProtocolStubFunction<(EraValidatorServiceProtocol, RuntimeCodingServiceProtocol), CompoundOperationWrapper> where M1.MatchedType == EraValidatorServiceProtocol, M2.MatchedType == RuntimeCodingServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(EraValidatorServiceProtocol, RuntimeCodingServiceProtocol)>] = [wrap(matchable: eraValidatorService) { $0.0 }, wrap(matchable: runtimeService) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockNetworkStakingInfoOperationFactoryProtocol.self, method: "networkStakingOperation(for: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + } + + func didStartLoadingValidatorInfo() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorOutputProtocol.self, method: "didStartLoadingValidatorInfo()", parameterMatchers: matchers)) + } + + func didReceiveValidatorInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorOutputProtocol.self, method: "didReceiveValidatorInfo(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_NetworkStakingInfoOperationFactoryProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorInfoInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -28611,15 +27583,27 @@ import RobinHood @discardableResult - func networkStakingOperation(for eraValidatorService: M1, runtimeService: M2) -> Cuckoo.__DoNotUse<(EraValidatorServiceProtocol, RuntimeCodingServiceProtocol), CompoundOperationWrapper> where M1.MatchedType == EraValidatorServiceProtocol, M2.MatchedType == RuntimeCodingServiceProtocol { - let matchers: [Cuckoo.ParameterMatcher<(EraValidatorServiceProtocol, RuntimeCodingServiceProtocol)>] = [wrap(matchable: eraValidatorService) { $0.0 }, wrap(matchable: runtimeService) { $0.1 }] - return cuckoo_manager.verify("networkStakingOperation(for: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didStartLoadingValidatorInfo() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoadingValidatorInfo()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveValidatorInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveValidatorInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class NetworkStakingInfoOperationFactoryProtocolStub: NetworkStakingInfoOperationFactoryProtocol { + class ValidatorInfoInteractorOutputProtocolStub: ValidatorInfoInteractorOutputProtocol { @@ -28627,33 +27611,39 @@ import RobinHood - func networkStakingOperation(for eraValidatorService: EraValidatorServiceProtocol, runtimeService: RuntimeCodingServiceProtocol) -> CompoundOperationWrapper { - return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper).self) + func didReceivePriceData(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStartLoadingValidatorInfo() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveValidatorInfo(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import Foundation -import RobinHood - - class MockValidatorOperationFactoryProtocol: ValidatorOperationFactoryProtocol, Cuckoo.ProtocolMock { + class MockValidatorInfoPresenterProtocol: ValidatorInfoPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorOperationFactoryProtocol + typealias MocksType = ValidatorInfoPresenterProtocol - typealias Stubbing = __StubbingProxy_ValidatorOperationFactoryProtocol - typealias Verification = __VerificationProxy_ValidatorOperationFactoryProtocol + typealias Stubbing = __StubbingProxy_ValidatorInfoPresenterProtocol + typealias Verification = __VerificationProxy_ValidatorInfoPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorOperationFactoryProtocol? + private var __defaultImplStub: ValidatorInfoPresenterProtocol? - func enableDefaultImplementation(_ stub: ValidatorOperationFactoryProtocol) { + func enableDefaultImplementation(_ stub: ValidatorInfoPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -28666,81 +27656,81 @@ import RobinHood - func allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]> { + func setup() { - return cuckoo_manager.call("allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]>", + return cuckoo_manager.call("setup()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.allElectedOperation()) + defaultCall: __defaultImplStub!.setup()) } - func allSelectedOperation(by nomination: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { + func reload() { - return cuckoo_manager.call("allSelectedOperation(by: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", - parameters: (nomination, nominatorAddress), - escapingParameters: (nomination, nominatorAddress), + return cuckoo_manager.call("reload()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.allSelectedOperation(by: nomination, nominatorAddress: nominatorAddress)) + defaultCall: __defaultImplStub!.reload()) } - func activeValidatorsOperation(for nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { + func presentAccountOptions() { - return cuckoo_manager.call("activeValidatorsOperation(for: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", - parameters: (nominatorAddress), - escapingParameters: (nominatorAddress), + return cuckoo_manager.call("presentAccountOptions()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.activeValidatorsOperation(for: nominatorAddress)) + defaultCall: __defaultImplStub!.presentAccountOptions()) } - func pendingValidatorsOperation(for accountIds: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { + func presentTotalStake() { - return cuckoo_manager.call("pendingValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", - parameters: (accountIds), - escapingParameters: (accountIds), + return cuckoo_manager.call("presentTotalStake()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.pendingValidatorsOperation(for: accountIds)) + defaultCall: __defaultImplStub!.presentTotalStake()) } - func wannabeValidatorsOperation(for accountIdList: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { + func presentIdentityItem(_ value: ValidatorInfoViewModel.IdentityItemValue) { - return cuckoo_manager.call("wannabeValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", - parameters: (accountIdList), - escapingParameters: (accountIdList), + return cuckoo_manager.call("presentIdentityItem(_: ValidatorInfoViewModel.IdentityItemValue)", + parameters: (value), + escapingParameters: (value), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.wannabeValidatorsOperation(for: accountIdList)) + defaultCall: __defaultImplStub!.presentIdentityItem(value)) } - struct __StubbingProxy_ValidatorOperationFactoryProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorInfoPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -28748,34 +27738,34 @@ import RobinHood } - func allElectedOperation() -> Cuckoo.ProtocolStubFunction<(), CompoundOperationWrapper<[ElectedValidatorInfo]>> { + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]>", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func allSelectedOperation(by nomination: M1, nominatorAddress: M2) -> Cuckoo.ProtocolStubFunction<(Nomination, AccountAddress), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == Nomination, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(Nomination, AccountAddress)>] = [wrap(matchable: nomination) { $0.0 }, wrap(matchable: nominatorAddress) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "allSelectedOperation(by: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", parameterMatchers: matchers)) + func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "reload()", parameterMatchers: matchers)) } - func activeValidatorsOperation(for nominatorAddress: M1) -> Cuckoo.ProtocolStubFunction<(AccountAddress), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: nominatorAddress) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "activeValidatorsOperation(for: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", parameterMatchers: matchers)) + func presentAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "presentAccountOptions()", parameterMatchers: matchers)) } - func pendingValidatorsOperation(for accountIds: M1) -> Cuckoo.ProtocolStubFunction<([AccountId]), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == [AccountId] { - let matchers: [Cuckoo.ParameterMatcher<([AccountId])>] = [wrap(matchable: accountIds) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "pendingValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", parameterMatchers: matchers)) + func presentTotalStake() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "presentTotalStake()", parameterMatchers: matchers)) } - func wannabeValidatorsOperation(for accountIdList: M1) -> Cuckoo.ProtocolStubFunction<([AccountId]), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == [AccountId] { - let matchers: [Cuckoo.ParameterMatcher<([AccountId])>] = [wrap(matchable: accountIdList) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorOperationFactoryProtocol.self, method: "wannabeValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", parameterMatchers: matchers)) + func presentIdentityItem(_ value: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoViewModel.IdentityItemValue)> where M1.MatchedType == ValidatorInfoViewModel.IdentityItemValue { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoViewModel.IdentityItemValue)>] = [wrap(matchable: value) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "presentIdentityItem(_: ValidatorInfoViewModel.IdentityItemValue)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ValidatorOperationFactoryProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorInfoPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -28790,39 +27780,39 @@ import RobinHood @discardableResult - func allElectedOperation() -> Cuckoo.__DoNotUse<(), CompoundOperationWrapper<[ElectedValidatorInfo]>> { + func setup() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func allSelectedOperation(by nomination: M1, nominatorAddress: M2) -> Cuckoo.__DoNotUse<(Nomination, AccountAddress), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == Nomination, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(Nomination, AccountAddress)>] = [wrap(matchable: nomination) { $0.0 }, wrap(matchable: nominatorAddress) { $0.1 }] - return cuckoo_manager.verify("allSelectedOperation(by: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func activeValidatorsOperation(for nominatorAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: nominatorAddress) { $0 }] - return cuckoo_manager.verify("activeValidatorsOperation(for: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func pendingValidatorsOperation(for accountIds: M1) -> Cuckoo.__DoNotUse<([AccountId]), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == [AccountId] { - let matchers: [Cuckoo.ParameterMatcher<([AccountId])>] = [wrap(matchable: accountIds) { $0 }] - return cuckoo_manager.verify("pendingValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentTotalStake() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentTotalStake()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func wannabeValidatorsOperation(for accountIdList: M1) -> Cuckoo.__DoNotUse<([AccountId]), CompoundOperationWrapper<[SelectedValidatorInfo]>> where M1.MatchedType == [AccountId] { - let matchers: [Cuckoo.ParameterMatcher<([AccountId])>] = [wrap(matchable: accountIdList) { $0 }] - return cuckoo_manager.verify("wannabeValidatorsOperation(for: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]>", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentIdentityItem(_ value: M1) -> Cuckoo.__DoNotUse<(ValidatorInfoViewModel.IdentityItemValue), Void> where M1.MatchedType == ValidatorInfoViewModel.IdentityItemValue { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoViewModel.IdentityItemValue)>] = [wrap(matchable: value) { $0 }] + return cuckoo_manager.verify("presentIdentityItem(_: ValidatorInfoViewModel.IdentityItemValue)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ValidatorOperationFactoryProtocolStub: ValidatorOperationFactoryProtocol { + class ValidatorInfoPresenterProtocolStub: ValidatorInfoPresenterProtocol { @@ -28830,83 +27820,237 @@ import RobinHood - func allElectedOperation() -> CompoundOperationWrapper<[ElectedValidatorInfo]> { - return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[ElectedValidatorInfo]>).self) + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func allSelectedOperation(by nomination: Nomination, nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { - return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[SelectedValidatorInfo]>).self) + func reload() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func activeValidatorsOperation(for nominatorAddress: AccountAddress) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { - return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[SelectedValidatorInfo]>).self) + func presentAccountOptions() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func pendingValidatorsOperation(for accountIds: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { - return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[SelectedValidatorInfo]>).self) + func presentTotalStake() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func wannabeValidatorsOperation(for accountIdList: [AccountId]) -> CompoundOperationWrapper<[SelectedValidatorInfo]> { - return DefaultValueRegistry.defaultValue(for: (CompoundOperationWrapper<[SelectedValidatorInfo]>).self) + func presentIdentityItem(_ value: ValidatorInfoViewModel.IdentityItemValue) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import SoraFoundation - - class MockCustomValidatorListViewProtocol: CustomValidatorListViewProtocol, Cuckoo.ProtocolMock { + class MockValidatorInfoWireframeProtocol: ValidatorInfoWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CustomValidatorListViewProtocol + typealias MocksType = ValidatorInfoWireframeProtocol - typealias Stubbing = __StubbingProxy_CustomValidatorListViewProtocol - typealias Verification = __VerificationProxy_CustomValidatorListViewProtocol + typealias Stubbing = __StubbingProxy_ValidatorInfoWireframeProtocol + typealias Verification = __VerificationProxy_ValidatorInfoWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CustomValidatorListViewProtocol? + private var __defaultImplStub: ValidatorInfoWireframeProtocol? - func enableDefaultImplementation(_ stub: CustomValidatorListViewProtocol) { + func enableDefaultImplementation(_ stub: ValidatorInfoWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - + + struct __StubbingProxy_ValidatorInfoWireframeProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + } + + struct __VerificationProxy_ValidatorInfoWireframeProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + } +} + + class ValidatorInfoWireframeProtocolStub: ValidatorInfoWireframeProtocol { + + + + + +} + + +import Cuckoo +@testable import novawallet + +import SoraFoundation + + + class MockValidatorListFilterWireframeProtocol: ValidatorListFilterWireframeProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = ValidatorListFilterWireframeProtocol + + typealias Stubbing = __StubbingProxy_ValidatorListFilterWireframeProtocol + typealias Verification = __VerificationProxy_ValidatorListFilterWireframeProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: ValidatorListFilterWireframeProtocol? + + func enableDefaultImplementation(_ stub: ValidatorListFilterWireframeProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + + + + + + + + + func close(_ view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("close(_: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.close(view)) + + } + + + struct __StubbingProxy_ValidatorListFilterWireframeProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func close(_ view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterWireframeProtocol.self, method: "close(_: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_ValidatorListFilterWireframeProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func close(_ view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(_: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class ValidatorListFilterWireframeProtocolStub: ValidatorListFilterWireframeProtocol { + + + + + + + + func close(_ view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + + + class MockValidatorListFilterViewProtocol: ValidatorListFilterViewProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = ValidatorListFilterViewProtocol + + typealias Stubbing = __StubbingProxy_ValidatorListFilterViewProtocol + typealias Verification = __VerificationProxy_ValidatorListFilterViewProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: ValidatorListFilterViewProtocol? + + func enableDefaultImplementation(_ stub: ValidatorListFilterViewProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + + + + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } + + + + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + Cuckoo.MockManager.crashOnProtocolSuperclassCall() , defaultCall: __defaultImplStub!.controller) @@ -28944,31 +28088,16 @@ import SoraFoundation - func reload(_ viewModel: CustomValidatorListViewModel, at indexes: [Int]?) { - - return cuckoo_manager.call("reload(_: CustomValidatorListViewModel, at: [Int]?)", - parameters: (viewModel, indexes), - escapingParameters: (viewModel, indexes), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.reload(viewModel, at: indexes)) - - } - - - - func setFilterAppliedState(to state: Bool) { + func didUpdateViewModel(_ viewModel: ValidatorListFilterViewModel) { - return cuckoo_manager.call("setFilterAppliedState(to: Bool)", - parameters: (state), - escapingParameters: (state), + return cuckoo_manager.call("didUpdateViewModel(_: ValidatorListFilterViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setFilterAppliedState(to: state)) + defaultCall: __defaultImplStub!.didUpdateViewModel(viewModel)) } @@ -28988,7 +28117,7 @@ import SoraFoundation } - struct __StubbingProxy_CustomValidatorListViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorListFilterViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -28996,39 +28125,34 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - func reload(_ viewModel: M1, at indexes: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(CustomValidatorListViewModel, [Int]?)> where M1.MatchedType == CustomValidatorListViewModel, M2.OptionalMatchedType == [Int] { - let matchers: [Cuckoo.ParameterMatcher<(CustomValidatorListViewModel, [Int]?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: indexes) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListViewProtocol.self, method: "reload(_: CustomValidatorListViewModel, at: [Int]?)", parameterMatchers: matchers)) - } - - func setFilterAppliedState(to state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: state) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListViewProtocol.self, method: "setFilterAppliedState(to: Bool)", parameterMatchers: matchers)) + func didUpdateViewModel(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorListFilterViewModel)> where M1.MatchedType == ValidatorListFilterViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterViewProtocol.self, method: "didUpdateViewModel(_: ValidatorListFilterViewModel)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CustomValidatorListViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorListFilterViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -29058,15 +28182,9 @@ import SoraFoundation @discardableResult - func reload(_ viewModel: M1, at indexes: M2) -> Cuckoo.__DoNotUse<(CustomValidatorListViewModel, [Int]?), Void> where M1.MatchedType == CustomValidatorListViewModel, M2.OptionalMatchedType == [Int] { - let matchers: [Cuckoo.ParameterMatcher<(CustomValidatorListViewModel, [Int]?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: indexes) { $0.1 }] - return cuckoo_manager.verify("reload(_: CustomValidatorListViewModel, at: [Int]?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func setFilterAppliedState(to state: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: state) { $0 }] - return cuckoo_manager.verify("setFilterAppliedState(to: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didUpdateViewModel(_ viewModel: M1) -> Cuckoo.__DoNotUse<(ValidatorListFilterViewModel), Void> where M1.MatchedType == ValidatorListFilterViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didUpdateViewModel(_: ValidatorListFilterViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -29078,7 +28196,7 @@ import SoraFoundation } } - class CustomValidatorListViewProtocolStub: CustomValidatorListViewProtocol { + class ValidatorListFilterViewProtocolStub: ValidatorListFilterViewProtocol { @@ -29115,13 +28233,7 @@ import SoraFoundation - func reload(_ viewModel: CustomValidatorListViewModel, at indexes: [Int]?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func setFilterAppliedState(to state: Bool) { + func didUpdateViewModel(_ viewModel: ValidatorListFilterViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -29135,181 +28247,169 @@ import SoraFoundation - class MockCustomValidatorListPresenterProtocol: CustomValidatorListPresenterProtocol, Cuckoo.ProtocolMock { + class MockValidatorListFilterPresenterProtocol: ValidatorListFilterPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CustomValidatorListPresenterProtocol + typealias MocksType = ValidatorListFilterPresenterProtocol - typealias Stubbing = __StubbingProxy_CustomValidatorListPresenterProtocol - typealias Verification = __VerificationProxy_CustomValidatorListPresenterProtocol + typealias Stubbing = __StubbingProxy_ValidatorListFilterPresenterProtocol + typealias Verification = __VerificationProxy_ValidatorListFilterPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CustomValidatorListPresenterProtocol? + private var __defaultImplStub: ValidatorListFilterPresenterProtocol? - func enableDefaultImplementation(_ stub: CustomValidatorListPresenterProtocol) { + func enableDefaultImplementation(_ stub: ValidatorListFilterPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - - - func setup() { + var view: ValidatorListFilterViewProtocol? { + get { + return cuckoo_manager.getter("view", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.view) + } - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) + set { + cuckoo_manager.setter("view", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.view = newValue) + } } - func fillWithRecommended() { + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } - return cuckoo_manager.call("fillWithRecommended()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.fillWithRecommended()) + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } } + - - func clearFilter() { - - return cuckoo_manager.call("clearFilter()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.clearFilter()) - - } + - func deselectAll() { + func setup() { - return cuckoo_manager.call("deselectAll()", + return cuckoo_manager.call("setup()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.deselectAll()) + defaultCall: __defaultImplStub!.setup()) } - func changeValidatorSelection(at index: Int) { + func toggleFilter(for viewModel: ValidatorListFilterCellViewModel) { - return cuckoo_manager.call("changeValidatorSelection(at: Int)", - parameters: (index), - escapingParameters: (index), + return cuckoo_manager.call("toggleFilter(for: ValidatorListFilterCellViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.changeValidatorSelection(at: index)) + defaultCall: __defaultImplStub!.toggleFilter(for: viewModel)) } - func didSelectValidator(at index: Int) { + func selectSorting(for viewModel: ValidatorListFilterCellViewModel) { - return cuckoo_manager.call("didSelectValidator(at: Int)", - parameters: (index), - escapingParameters: (index), + return cuckoo_manager.call("selectSorting(for: ValidatorListFilterCellViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didSelectValidator(at: index)) + defaultCall: __defaultImplStub!.selectSorting(for: viewModel)) } - func presentFilter() { + func applyFilter() { - return cuckoo_manager.call("presentFilter()", + return cuckoo_manager.call("applyFilter()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentFilter()) + defaultCall: __defaultImplStub!.applyFilter()) } - func presentSearch() { + func resetFilter() { - return cuckoo_manager.call("presentSearch()", + return cuckoo_manager.call("resetFilter()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentSearch()) + defaultCall: __defaultImplStub!.resetFilter()) } - func proceed() { + public func applyLocalization() { - return cuckoo_manager.call("proceed()", + return cuckoo_manager.call("applyLocalization()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) - - } - - - - func didRemove(_ validator: SelectedValidatorInfo) { - - return cuckoo_manager.call("didRemove(_: SelectedValidatorInfo)", - parameters: (validator), - escapingParameters: (validator), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didRemove(validator)) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_CustomValidatorListPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorListFilterPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -29317,59 +28417,49 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + var view: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "view") } - func fillWithRecommended() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "fillWithRecommended()", parameterMatchers: matchers)) - } - func clearFilter() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "clearFilter()", parameterMatchers: matchers)) + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func deselectAll() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "deselectAll()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func changeValidatorSelection(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "changeValidatorSelection(at: Int)", parameterMatchers: matchers)) + func toggleFilter(for viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorListFilterCellViewModel)> where M1.MatchedType == ValidatorListFilterCellViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterCellViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "toggleFilter(for: ValidatorListFilterCellViewModel)", parameterMatchers: matchers)) } - func didSelectValidator(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "didSelectValidator(at: Int)", parameterMatchers: matchers)) + func selectSorting(for viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorListFilterCellViewModel)> where M1.MatchedType == ValidatorListFilterCellViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterCellViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "selectSorting(for: ValidatorListFilterCellViewModel)", parameterMatchers: matchers)) } - func presentFilter() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func applyFilter() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "presentFilter()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "applyFilter()", parameterMatchers: matchers)) } - func presentSearch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func resetFilter() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "presentSearch()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "resetFilter()", parameterMatchers: matchers)) } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) - } - - func didRemove(_ validator: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorInfo)> where M1.MatchedType == SelectedValidatorInfo { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo)>] = [wrap(matchable: validator) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListPresenterProtocol.self, method: "didRemove(_: SelectedValidatorInfo)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CustomValidatorListPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorListFilterPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -29381,134 +28471,118 @@ import SoraFoundation } - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var view: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "view", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func fillWithRecommended() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("fillWithRecommended()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - @discardableResult - func clearFilter() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("clearFilter()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + @discardableResult - func deselectAll() -> Cuckoo.__DoNotUse<(), Void> { + func setup() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("deselectAll()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func changeValidatorSelection(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("changeValidatorSelection(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func toggleFilter(for viewModel: M1) -> Cuckoo.__DoNotUse<(ValidatorListFilterCellViewModel), Void> where M1.MatchedType == ValidatorListFilterCellViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterCellViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("toggleFilter(for: ValidatorListFilterCellViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didSelectValidator(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("didSelectValidator(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectSorting(for viewModel: M1) -> Cuckoo.__DoNotUse<(ValidatorListFilterCellViewModel), Void> where M1.MatchedType == ValidatorListFilterCellViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterCellViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("selectSorting(for: ValidatorListFilterCellViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentFilter() -> Cuckoo.__DoNotUse<(), Void> { + func applyFilter() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentFilter()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("applyFilter()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentSearch() -> Cuckoo.__DoNotUse<(), Void> { + func resetFilter() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentSearch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("resetFilter()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didRemove(_ validator: M1) -> Cuckoo.__DoNotUse<(SelectedValidatorInfo), Void> where M1.MatchedType == SelectedValidatorInfo { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo)>] = [wrap(matchable: validator) { $0 }] - return cuckoo_manager.verify("didRemove(_: SelectedValidatorInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CustomValidatorListPresenterProtocolStub: CustomValidatorListPresenterProtocol { - - + class ValidatorListFilterPresenterProtocolStub: ValidatorListFilterPresenterProtocol { + - + var view: ValidatorListFilterViewProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (ValidatorListFilterViewProtocol?).self) + } + + set { } + + } + - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func fillWithRecommended() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func clearFilter() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + } + - - func deselectAll() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func changeValidatorSelection(at index: Int) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didSelectValidator(at index: Int) { + func toggleFilter(for viewModel: ValidatorListFilterCellViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentFilter() { + func selectSorting(for viewModel: ValidatorListFilterCellViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentSearch() { + func applyFilter() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func proceed() { + func resetFilter() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didRemove(_ validator: SelectedValidatorInfo) { + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -29516,19 +28590,19 @@ import SoraFoundation - class MockCustomValidatorListViewModelFactoryProtocol: CustomValidatorListViewModelFactoryProtocol, Cuckoo.ProtocolMock { + class MockValidatorListFilterDelegate: ValidatorListFilterDelegate, Cuckoo.ProtocolMock { - typealias MocksType = CustomValidatorListViewModelFactoryProtocol + typealias MocksType = ValidatorListFilterDelegate - typealias Stubbing = __StubbingProxy_CustomValidatorListViewModelFactoryProtocol - typealias Verification = __VerificationProxy_CustomValidatorListViewModelFactoryProtocol + typealias Stubbing = __StubbingProxy_ValidatorListFilterDelegate + typealias Verification = __VerificationProxy_ValidatorListFilterDelegate let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CustomValidatorListViewModelFactoryProtocol? + private var __defaultImplStub: ValidatorListFilterDelegate? - func enableDefaultImplementation(_ stub: CustomValidatorListViewModelFactoryProtocol) { + func enableDefaultImplementation(_ stub: ValidatorListFilterDelegate) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -29541,21 +28615,21 @@ import SoraFoundation - func createViewModel(from validatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel { + func didUpdate(_ filter: CustomValidatorListFilter) { - return cuckoo_manager.call("createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel", - parameters: (validatorList, selectedValidatorList, totalValidatorsCount, filter, priceData, locale), - escapingParameters: (validatorList, selectedValidatorList, totalValidatorsCount, filter, priceData, locale), + return cuckoo_manager.call("didUpdate(_: CustomValidatorListFilter)", + parameters: (filter), + escapingParameters: (filter), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.createViewModel(from: validatorList, selectedValidatorList: selectedValidatorList, totalValidatorsCount: totalValidatorsCount, filter: filter, priceData: priceData, locale: locale)) + defaultCall: __defaultImplStub!.didUpdate(filter)) } - struct __StubbingProxy_CustomValidatorListViewModelFactoryProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorListFilterDelegate: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -29563,14 +28637,14 @@ import SoraFoundation } - func createViewModel(from validatorList: M1, selectedValidatorList: M2, totalValidatorsCount: M3, filter: M4, priceData: M5, locale: M6) -> Cuckoo.ProtocolStubFunction<([SelectedValidatorInfo], [SelectedValidatorInfo], Int, CustomValidatorListFilter, PriceData?, Locale), CustomValidatorListViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int, M4.MatchedType == CustomValidatorListFilter, M5.OptionalMatchedType == PriceData, M6.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], [SelectedValidatorInfo], Int, CustomValidatorListFilter, PriceData?, Locale)>] = [wrap(matchable: validatorList) { $0.0 }, wrap(matchable: selectedValidatorList) { $0.1 }, wrap(matchable: totalValidatorsCount) { $0.2 }, wrap(matchable: filter) { $0.3 }, wrap(matchable: priceData) { $0.4 }, wrap(matchable: locale) { $0.5 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListViewModelFactoryProtocol.self, method: "createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel", parameterMatchers: matchers)) + func didUpdate(_ filter: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CustomValidatorListFilter)> where M1.MatchedType == CustomValidatorListFilter { + let matchers: [Cuckoo.ParameterMatcher<(CustomValidatorListFilter)>] = [wrap(matchable: filter) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterDelegate.self, method: "didUpdate(_: CustomValidatorListFilter)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CustomValidatorListViewModelFactoryProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorListFilterDelegate: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -29585,15 +28659,15 @@ import SoraFoundation @discardableResult - func createViewModel(from validatorList: M1, selectedValidatorList: M2, totalValidatorsCount: M3, filter: M4, priceData: M5, locale: M6) -> Cuckoo.__DoNotUse<([SelectedValidatorInfo], [SelectedValidatorInfo], Int, CustomValidatorListFilter, PriceData?, Locale), CustomValidatorListViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int, M4.MatchedType == CustomValidatorListFilter, M5.OptionalMatchedType == PriceData, M6.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], [SelectedValidatorInfo], Int, CustomValidatorListFilter, PriceData?, Locale)>] = [wrap(matchable: validatorList) { $0.0 }, wrap(matchable: selectedValidatorList) { $0.1 }, wrap(matchable: totalValidatorsCount) { $0.2 }, wrap(matchable: filter) { $0.3 }, wrap(matchable: priceData) { $0.4 }, wrap(matchable: locale) { $0.5 }] - return cuckoo_manager.verify("createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didUpdate(_ filter: M1) -> Cuckoo.__DoNotUse<(CustomValidatorListFilter), Void> where M1.MatchedType == CustomValidatorListFilter { + let matchers: [Cuckoo.ParameterMatcher<(CustomValidatorListFilter)>] = [wrap(matchable: filter) { $0 }] + return cuckoo_manager.verify("didUpdate(_: CustomValidatorListFilter)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CustomValidatorListViewModelFactoryProtocolStub: CustomValidatorListViewModelFactoryProtocol { + class ValidatorListFilterDelegateStub: ValidatorListFilterDelegate { @@ -29601,27 +28675,32 @@ import SoraFoundation - func createViewModel(from validatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, filter: CustomValidatorListFilter, priceData: PriceData?, locale: Locale) -> CustomValidatorListViewModel { - return DefaultValueRegistry.defaultValue(for: (CustomValidatorListViewModel).self) + func didUpdate(_ filter: CustomValidatorListFilter) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet + +import SoraFoundation + - class MockCustomValidatorListInteractorInputProtocol: CustomValidatorListInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockValidatorSearchWireframeProtocol: ValidatorSearchWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CustomValidatorListInteractorInputProtocol + typealias MocksType = ValidatorSearchWireframeProtocol - typealias Stubbing = __StubbingProxy_CustomValidatorListInteractorInputProtocol - typealias Verification = __VerificationProxy_CustomValidatorListInteractorInputProtocol + typealias Stubbing = __StubbingProxy_ValidatorSearchWireframeProtocol + typealias Verification = __VerificationProxy_ValidatorSearchWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CustomValidatorListInteractorInputProtocol? + private var __defaultImplStub: ValidatorSearchWireframeProtocol? - func enableDefaultImplementation(_ stub: CustomValidatorListInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: ValidatorSearchWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -29634,21 +28713,66 @@ import SoraFoundation - func setup() { + func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", + parameters: (validatorInfo, view), + escapingParameters: (validatorInfo, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) + + } + + + + func close(_ view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("close(_: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.close(view)) + + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_CustomValidatorListInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorSearchWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -29656,14 +28780,29 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoProtocol, ControllerBackedProtocol?)> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchWireframeProtocol.self, method: "present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func close(_ view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchWireframeProtocol.self, method: "close(_: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_CustomValidatorListInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorSearchWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -29678,15 +28817,33 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(ValidatorInfoProtocol, ControllerBackedProtocol?), Void> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func close(_ view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(_: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CustomValidatorListInteractorInputProtocolStub: CustomValidatorListInteractorInputProtocol { + class ValidatorSearchWireframeProtocolStub: ValidatorSearchWireframeProtocol { @@ -29694,7 +28851,25 @@ import SoraFoundation - func setup() { + func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func close(_ view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -29702,19 +28877,19 @@ import SoraFoundation - class MockCustomValidatorListInteractorOutputProtocol: CustomValidatorListInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockValidatorSearchDelegate: ValidatorSearchDelegate, Cuckoo.ProtocolMock { - typealias MocksType = CustomValidatorListInteractorOutputProtocol + typealias MocksType = ValidatorSearchDelegate - typealias Stubbing = __StubbingProxy_CustomValidatorListInteractorOutputProtocol - typealias Verification = __VerificationProxy_CustomValidatorListInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_ValidatorSearchDelegate + typealias Verification = __VerificationProxy_ValidatorSearchDelegate let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CustomValidatorListInteractorOutputProtocol? + private var __defaultImplStub: ValidatorSearchDelegate? - func enableDefaultImplementation(_ stub: CustomValidatorListInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: ValidatorSearchDelegate) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -29727,21 +28902,21 @@ import SoraFoundation - func didReceivePriceData(result: Result) { + func validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo]) { - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo])", + parameters: (selectedValidatorList), + escapingParameters: (selectedValidatorList), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + defaultCall: __defaultImplStub!.validatorSearchDidUpdate(selectedValidatorList: selectedValidatorList)) } - struct __StubbingProxy_CustomValidatorListInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorSearchDelegate: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -29749,14 +28924,14 @@ import SoraFoundation } - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + func validatorSearchDidUpdate(selectedValidatorList: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([SelectedValidatorInfo])> where M1.MatchedType == [SelectedValidatorInfo] { + let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo])>] = [wrap(matchable: selectedValidatorList) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchDelegate.self, method: "validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo])", parameterMatchers: matchers)) } } - struct __VerificationProxy_CustomValidatorListInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorSearchDelegate: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -29771,15 +28946,15 @@ import SoraFoundation @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func validatorSearchDidUpdate(selectedValidatorList: M1) -> Cuckoo.__DoNotUse<([SelectedValidatorInfo]), Void> where M1.MatchedType == [SelectedValidatorInfo] { + let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo])>] = [wrap(matchable: selectedValidatorList) { $0 }] + return cuckoo_manager.verify("validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CustomValidatorListInteractorOutputProtocolStub: CustomValidatorListInteractorOutputProtocol { + class ValidatorSearchDelegateStub: ValidatorSearchDelegate { @@ -29787,7 +28962,7 @@ import SoraFoundation - func didReceivePriceData(result: Result) { + func validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo]) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -29795,121 +28970,158 @@ import SoraFoundation - class MockCustomValidatorListWireframeProtocol: CustomValidatorListWireframeProtocol, Cuckoo.ProtocolMock { + class MockValidatorSearchViewProtocol: ValidatorSearchViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = CustomValidatorListWireframeProtocol + typealias MocksType = ValidatorSearchViewProtocol - typealias Stubbing = __StubbingProxy_CustomValidatorListWireframeProtocol - typealias Verification = __VerificationProxy_CustomValidatorListWireframeProtocol + typealias Stubbing = __StubbingProxy_ValidatorSearchViewProtocol + typealias Verification = __VerificationProxy_ValidatorSearchViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: CustomValidatorListWireframeProtocol? + private var __defaultImplStub: ValidatorSearchViewProtocol? - func enableDefaultImplementation(_ stub: CustomValidatorListWireframeProtocol) { + func enableDefaultImplementation(_ stub: ValidatorSearchViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } - func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } - return cuckoo_manager.call("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", - parameters: (validatorInfo, view), - escapingParameters: (validatorInfo, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) + } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } + + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } } + + + - func presentFilters(from view: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?) { + + func didReload(_ viewModel: ValidatorSearchViewModel) { - return cuckoo_manager.call("presentFilters(from: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?)", - parameters: (view, filter, hasIdentity, delegate), - escapingParameters: (view, filter, hasIdentity, delegate), + return cuckoo_manager.call("didReload(_: ValidatorSearchViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentFilters(from: view, filter: filter, hasIdentity: hasIdentity, delegate: delegate)) + defaultCall: __defaultImplStub!.didReload(viewModel)) } - func presentSearch(from view: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?) { + func didStartSearch() { - return cuckoo_manager.call("presentSearch(from: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?)", - parameters: (view, fullValidatorList, selectedValidatorList, delegate), - escapingParameters: (view, fullValidatorList, selectedValidatorList, delegate), + return cuckoo_manager.call("didStartSearch()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentSearch(from: view, fullValidatorList: fullValidatorList, selectedValidatorList: selectedValidatorList, delegate: delegate)) + defaultCall: __defaultImplStub!.didStartSearch()) } - func proceed(from view: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate) { + func didStopSearch() { - return cuckoo_manager.call("proceed(from: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate)", - parameters: (view, validatorList, maxTargets, delegate), - escapingParameters: (view, validatorList, maxTargets, delegate), + return cuckoo_manager.call("didStopSearch()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed(from: view, validatorList: validatorList, maxTargets: maxTargets, delegate: delegate)) + defaultCall: __defaultImplStub!.didStopSearch()) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func didReset() { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("didReset()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.didReset()) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + public func applyLocalization() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_CustomValidatorListWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorSearchViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -29917,39 +29129,49 @@ import SoraFoundation } - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoProtocol, ControllerBackedProtocol?)> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func presentFilters(from view: M1, filter: M2, hasIdentity: M3, delegate: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, CustomValidatorListFilter, Bool, ValidatorListFilterDelegate?)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == CustomValidatorListFilter, M3.MatchedType == Bool, M4.OptionalMatchedType == ValidatorListFilterDelegate { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, CustomValidatorListFilter, Bool, ValidatorListFilterDelegate?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: filter) { $0.1 }, wrap(matchable: hasIdentity) { $0.2 }, wrap(matchable: delegate) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "presentFilters(from: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?)", parameterMatchers: matchers)) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func presentSearch(from view: M1, fullValidatorList: M2, selectedValidatorList: M3, delegate: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, [SelectedValidatorInfo], [SelectedValidatorInfo], ValidatorSearchDelegate?)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == [SelectedValidatorInfo], M4.OptionalMatchedType == ValidatorSearchDelegate { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, [SelectedValidatorInfo], [SelectedValidatorInfo], ValidatorSearchDelegate?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: fullValidatorList) { $0.1 }, wrap(matchable: selectedValidatorList) { $0.2 }, wrap(matchable: delegate) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "presentSearch(from: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?)", parameterMatchers: matchers)) + + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func proceed(from view: M1, validatorList: M2, maxTargets: M3, delegate: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, [SelectedValidatorInfo], Int, SelectedValidatorListDelegate)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int, M4.MatchedType == SelectedValidatorListDelegate { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, [SelectedValidatorInfo], Int, SelectedValidatorListDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: validatorList) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }, wrap(matchable: delegate) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "proceed(from: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate)", parameterMatchers: matchers)) + + func didReload(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorSearchViewModel)> where M1.MatchedType == ValidatorSearchViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorSearchViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "didReload(_: ValidatorSearchViewModel)", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didStartSearch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "didStartSearch()", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockCustomValidatorListWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didStopSearch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "didStopSearch()", parameterMatchers: matchers)) + } + + func didReset() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "didReset()", parameterMatchers: matchers)) + } + + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_CustomValidatorListWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorSearchViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -29961,205 +29183,258 @@ import SoraFoundation } - - @discardableResult - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(ValidatorInfoProtocol, ControllerBackedProtocol?), Void> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + @discardableResult - func presentFilters(from view: M1, filter: M2, hasIdentity: M3, delegate: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, CustomValidatorListFilter, Bool, ValidatorListFilterDelegate?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == CustomValidatorListFilter, M3.MatchedType == Bool, M4.OptionalMatchedType == ValidatorListFilterDelegate { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, CustomValidatorListFilter, Bool, ValidatorListFilterDelegate?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: filter) { $0.1 }, wrap(matchable: hasIdentity) { $0.2 }, wrap(matchable: delegate) { $0.3 }] - return cuckoo_manager.verify("presentFilters(from: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReload(_ viewModel: M1) -> Cuckoo.__DoNotUse<(ValidatorSearchViewModel), Void> where M1.MatchedType == ValidatorSearchViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorSearchViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReload(_: ValidatorSearchViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentSearch(from view: M1, fullValidatorList: M2, selectedValidatorList: M3, delegate: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, [SelectedValidatorInfo], [SelectedValidatorInfo], ValidatorSearchDelegate?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == [SelectedValidatorInfo], M4.OptionalMatchedType == ValidatorSearchDelegate { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, [SelectedValidatorInfo], [SelectedValidatorInfo], ValidatorSearchDelegate?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: fullValidatorList) { $0.1 }, wrap(matchable: selectedValidatorList) { $0.2 }, wrap(matchable: delegate) { $0.3 }] - return cuckoo_manager.verify("presentSearch(from: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStartSearch() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartSearch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceed(from view: M1, validatorList: M2, maxTargets: M3, delegate: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, [SelectedValidatorInfo], Int, SelectedValidatorListDelegate), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int, M4.MatchedType == SelectedValidatorListDelegate { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, [SelectedValidatorInfo], Int, SelectedValidatorListDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: validatorList) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }, wrap(matchable: delegate) { $0.3 }] - return cuckoo_manager.verify("proceed(from: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStopSearch() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopSearch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReset() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didReset()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class CustomValidatorListWireframeProtocolStub: CustomValidatorListWireframeProtocol { - - - - - + class ValidatorSearchViewProtocolStub: ValidatorSearchViewProtocol { + - func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + } + - - func presentFilters(from view: ControllerBackedProtocol?, filter: CustomValidatorListFilter, hasIdentity: Bool, delegate: ValidatorListFilterDelegate?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } - func presentSearch(from view: ControllerBackedProtocol?, fullValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], delegate: ValidatorSearchDelegate?) { + + + + + + + func didReload(_ viewModel: ValidatorSearchViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func proceed(from view: ControllerBackedProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int, delegate: SelectedValidatorListDelegate) { + func didStartSearch() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func didStopSearch() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didReset() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import SoraFoundation - - class MockRecommendedValidatorListViewProtocol: RecommendedValidatorListViewProtocol, Cuckoo.ProtocolMock { + class MockValidatorSearchInteractorInputProtocol: ValidatorSearchInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = RecommendedValidatorListViewProtocol + typealias MocksType = ValidatorSearchInteractorInputProtocol - typealias Stubbing = __StubbingProxy_RecommendedValidatorListViewProtocol - typealias Verification = __VerificationProxy_RecommendedValidatorListViewProtocol + typealias Stubbing = __StubbingProxy_ValidatorSearchInteractorInputProtocol + typealias Verification = __VerificationProxy_ValidatorSearchInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: RecommendedValidatorListViewProtocol? + private var __defaultImplStub: ValidatorSearchInteractorInputProtocol? - func enableDefaultImplementation(_ stub: RecommendedValidatorListViewProtocol) { + func enableDefaultImplementation(_ stub: ValidatorSearchInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } + + + func performValidatorSearch(accountId: AccountId) { + + return cuckoo_manager.call("performValidatorSearch(accountId: AccountId)", + parameters: (accountId), + escapingParameters: (accountId), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performValidatorSearch(accountId: accountId)) } + + struct __StubbingProxy_ValidatorSearchInteractorInputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func performValidatorSearch(accountId: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountId)> where M1.MatchedType == AccountId { + let matchers: [Cuckoo.ParameterMatcher<(AccountId)>] = [wrap(matchable: accountId) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchInteractorInputProtocol.self, method: "performValidatorSearch(accountId: AccountId)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_ValidatorSearchInteractorInputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func performValidatorSearch(accountId: M1) -> Cuckoo.__DoNotUse<(AccountId), Void> where M1.MatchedType == AccountId { + let matchers: [Cuckoo.ParameterMatcher<(AccountId)>] = [wrap(matchable: accountId) { $0 }] + return cuckoo_manager.verify("performValidatorSearch(accountId: AccountId)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class ValidatorSearchInteractorInputProtocolStub: ValidatorSearchInteractorInputProtocol { + - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } + - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } - - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } - + func performValidatorSearch(accountId: AccountId) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + - + class MockValidatorSearchInteractorOutputProtocol: ValidatorSearchInteractorOutputProtocol, Cuckoo.ProtocolMock { + typealias MocksType = ValidatorSearchInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_ValidatorSearchInteractorOutputProtocol + typealias Verification = __VerificationProxy_ValidatorSearchInteractorOutputProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func didReceive(viewModel: RecommendedValidatorListViewModelProtocol) { - - return cuckoo_manager.call("didReceive(viewModel: RecommendedValidatorListViewModelProtocol)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) - + private var __defaultImplStub: ValidatorSearchInteractorOutputProtocol? + + func enableDefaultImplementation(_ stub: ValidatorSearchInteractorOutputProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - public func applyLocalization() { + + + + + func didReceiveValidatorInfo(result: Result) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveValidatorInfo(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.didReceiveValidatorInfo(result: result)) } - struct __StubbingProxy_RecommendedValidatorListViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorSearchInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -30167,34 +29442,14 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") - } - - - func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RecommendedValidatorListViewModelProtocol)> where M1.MatchedType == RecommendedValidatorListViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(RecommendedValidatorListViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListViewProtocol.self, method: "didReceive(viewModel: RecommendedValidatorListViewModelProtocol)", parameterMatchers: matchers)) - } - - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func didReceiveValidatorInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchInteractorOutputProtocol.self, method: "didReceiveValidatorInfo(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_RecommendedValidatorListViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorSearchInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -30206,68 +29461,18 @@ import SoraFoundation } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(RecommendedValidatorListViewModelProtocol), Void> where M1.MatchedType == RecommendedValidatorListViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(RecommendedValidatorListViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceive(viewModel: RecommendedValidatorListViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveValidatorInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveValidatorInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class RecommendedValidatorListViewProtocolStub: RecommendedValidatorListViewProtocol { - - - - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - - - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - - } + class ValidatorSearchInteractorOutputProtocolStub: ValidatorSearchInteractorOutputProtocol { @@ -30275,13 +29480,7 @@ import SoraFoundation - func didReceive(viewModel: RecommendedValidatorListViewModelProtocol) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - public func applyLocalization() { + func didReceiveValidatorInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -30289,25 +29488,49 @@ import SoraFoundation - class MockRecommendedValidatorListPresenterProtocol: RecommendedValidatorListPresenterProtocol, Cuckoo.ProtocolMock { + class MockValidatorSearchPresenterProtocol: ValidatorSearchPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = RecommendedValidatorListPresenterProtocol + typealias MocksType = ValidatorSearchPresenterProtocol - typealias Stubbing = __StubbingProxy_RecommendedValidatorListPresenterProtocol - typealias Verification = __VerificationProxy_RecommendedValidatorListPresenterProtocol + typealias Stubbing = __StubbingProxy_ValidatorSearchPresenterProtocol + typealias Verification = __VerificationProxy_ValidatorSearchPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: RecommendedValidatorListPresenterProtocol? + private var __defaultImplStub: ValidatorSearchPresenterProtocol? - func enableDefaultImplementation(_ stub: RecommendedValidatorListPresenterProtocol) { + func enableDefaultImplementation(_ stub: ValidatorSearchPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } + + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } + + } + @@ -30329,36 +29552,81 @@ import SoraFoundation - func selectedValidatorAt(index: Int) { + func changeValidatorSelection(at index: Int) { - return cuckoo_manager.call("selectedValidatorAt(index: Int)", + return cuckoo_manager.call("changeValidatorSelection(at: Int)", parameters: (index), escapingParameters: (index), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectedValidatorAt(index: index)) + defaultCall: __defaultImplStub!.changeValidatorSelection(at: index)) } - func proceed() { + func search(for textEntry: String) { - return cuckoo_manager.call("proceed()", + return cuckoo_manager.call("search(for: String)", + parameters: (textEntry), + escapingParameters: (textEntry), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.search(for: textEntry)) + + } + + + + func didSelectValidator(at index: Int) { + + return cuckoo_manager.call("didSelectValidator(at: Int)", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didSelectValidator(at: index)) + + } + + + + func applyChanges() { + + return cuckoo_manager.call("applyChanges()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.applyChanges()) + + } + + + + public func applyLocalization() { + + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_RecommendedValidatorListPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorSearchPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -30366,24 +29634,44 @@ import SoraFoundation } + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") + } + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func selectedValidatorAt(index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + func changeValidatorSelection(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListPresenterProtocol.self, method: "selectedValidatorAt(index: Int)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "changeValidatorSelection(at: Int)", parameterMatchers: matchers)) } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func search(for textEntry: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: textEntry) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "search(for: String)", parameterMatchers: matchers)) + } + + func didSelectValidator(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "didSelectValidator(at: Int)", parameterMatchers: matchers)) + } + + func applyChanges() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "applyChanges()", parameterMatchers: matchers)) + } + + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_RecommendedValidatorListPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorSearchPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -30395,6 +29683,11 @@ import SoraFoundation } + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult @@ -30404,21 +29697,50 @@ import SoraFoundation } @discardableResult - func selectedValidatorAt(index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + func changeValidatorSelection(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("selectedValidatorAt(index: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("changeValidatorSelection(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { + func search(for textEntry: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: textEntry) { $0 }] + return cuckoo_manager.verify("search(for: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didSelectValidator(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("didSelectValidator(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func applyChanges() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("applyChanges()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class RecommendedValidatorListPresenterProtocolStub: RecommendedValidatorListPresenterProtocol { + class ValidatorSearchPresenterProtocolStub: ValidatorSearchPresenterProtocol { + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } @@ -30432,13 +29754,31 @@ import SoraFoundation - func selectedValidatorAt(index: Int) { + func changeValidatorSelection(at index: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func proceed() { + func search(for textEntry: String) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didSelectValidator(at index: Int) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func applyChanges() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -30446,19 +29786,19 @@ import SoraFoundation - class MockRecommendedValidatorListWireframeProtocol: RecommendedValidatorListWireframeProtocol, Cuckoo.ProtocolMock { + class MockValidatorSearchViewModelFactoryProtocol: ValidatorSearchViewModelFactoryProtocol, Cuckoo.ProtocolMock { - typealias MocksType = RecommendedValidatorListWireframeProtocol + typealias MocksType = ValidatorSearchViewModelFactoryProtocol - typealias Stubbing = __StubbingProxy_RecommendedValidatorListWireframeProtocol - typealias Verification = __VerificationProxy_RecommendedValidatorListWireframeProtocol + typealias Stubbing = __StubbingProxy_ValidatorSearchViewModelFactoryProtocol + typealias Verification = __VerificationProxy_ValidatorSearchViewModelFactoryProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: RecommendedValidatorListWireframeProtocol? + private var __defaultImplStub: ValidatorSearchViewModelFactoryProtocol? - func enableDefaultImplementation(_ stub: RecommendedValidatorListWireframeProtocol) { + func enableDefaultImplementation(_ stub: ValidatorSearchViewModelFactoryProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -30471,36 +29811,21 @@ import SoraFoundation - func present(_ validatorInfo: SelectedValidatorInfo, from view: RecommendedValidatorListViewProtocol?) { - - return cuckoo_manager.call("present(_: SelectedValidatorInfo, from: RecommendedValidatorListViewProtocol?)", - parameters: (validatorInfo, view), - escapingParameters: (validatorInfo, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) - - } - - - - func proceed(from view: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int) { + func createViewModel(from displayValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel { - return cuckoo_manager.call("proceed(from: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", - parameters: (view, targets, maxTargets), - escapingParameters: (view, targets, maxTargets), + return cuckoo_manager.call("createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel", + parameters: (displayValidatorList, selectedValidatorList, locale), + escapingParameters: (displayValidatorList, selectedValidatorList, locale), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed(from: view, targets: targets, maxTargets: maxTargets)) + defaultCall: __defaultImplStub!.createViewModel(from: displayValidatorList, selectedValidatorList: selectedValidatorList, locale: locale)) } - struct __StubbingProxy_RecommendedValidatorListWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ValidatorSearchViewModelFactoryProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -30508,19 +29833,14 @@ import SoraFoundation } - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorInfo, RecommendedValidatorListViewProtocol?)> where M1.MatchedType == SelectedValidatorInfo, M2.OptionalMatchedType == RecommendedValidatorListViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo, RecommendedValidatorListViewProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListWireframeProtocol.self, method: "present(_: SelectedValidatorInfo, from: RecommendedValidatorListViewProtocol?)", parameterMatchers: matchers)) - } - - func proceed(from view: M1, targets: M2, maxTargets: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(RecommendedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)> where M1.OptionalMatchedType == RecommendedValidatorListViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(RecommendedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: targets) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockRecommendedValidatorListWireframeProtocol.self, method: "proceed(from: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", parameterMatchers: matchers)) + func createViewModel(from displayValidatorList: M1, selectedValidatorList: M2, locale: M3) -> Cuckoo.ProtocolStubFunction<([SelectedValidatorInfo], [SelectedValidatorInfo], Locale), ValidatorSearchViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], [SelectedValidatorInfo], Locale)>] = [wrap(matchable: displayValidatorList) { $0.0 }, wrap(matchable: selectedValidatorList) { $0.1 }, wrap(matchable: locale) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewModelFactoryProtocol.self, method: "createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel", parameterMatchers: matchers)) } } - struct __VerificationProxy_RecommendedValidatorListWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ValidatorSearchViewModelFactoryProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -30535,21 +29855,15 @@ import SoraFoundation @discardableResult - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(SelectedValidatorInfo, RecommendedValidatorListViewProtocol?), Void> where M1.MatchedType == SelectedValidatorInfo, M2.OptionalMatchedType == RecommendedValidatorListViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo, RecommendedValidatorListViewProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("present(_: SelectedValidatorInfo, from: RecommendedValidatorListViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func proceed(from view: M1, targets: M2, maxTargets: M3) -> Cuckoo.__DoNotUse<(RecommendedValidatorListViewProtocol?, [SelectedValidatorInfo], Int), Void> where M1.OptionalMatchedType == RecommendedValidatorListViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(RecommendedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: targets) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] - return cuckoo_manager.verify("proceed(from: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func createViewModel(from displayValidatorList: M1, selectedValidatorList: M2, locale: M3) -> Cuckoo.__DoNotUse<([SelectedValidatorInfo], [SelectedValidatorInfo], Locale), ValidatorSearchViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], [SelectedValidatorInfo], Locale)>] = [wrap(matchable: displayValidatorList) { $0.0 }, wrap(matchable: selectedValidatorList) { $0.1 }, wrap(matchable: locale) { $0.2 }] + return cuckoo_manager.verify("createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class RecommendedValidatorListWireframeProtocolStub: RecommendedValidatorListWireframeProtocol { + class ValidatorSearchViewModelFactoryProtocolStub: ValidatorSearchViewModelFactoryProtocol { @@ -30557,14 +29871,8 @@ import SoraFoundation - func present(_ validatorInfo: SelectedValidatorInfo, from view: RecommendedValidatorListViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func proceed(from view: RecommendedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func createViewModel(from displayValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel { + return DefaultValueRegistry.defaultValue(for: (ValidatorSearchViewModel).self) } } @@ -30573,24 +29881,22 @@ import SoraFoundation import Cuckoo @testable import novawallet -import BigInt -import Foundation import SoraFoundation - class MockSelectValidatorsConfirmViewProtocol: SelectValidatorsConfirmViewProtocol, Cuckoo.ProtocolMock { + class MockYourValidatorListViewProtocol: YourValidatorListViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsConfirmViewProtocol + typealias MocksType = YourValidatorListViewProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmViewProtocol - typealias Verification = __VerificationProxy_SelectValidatorsConfirmViewProtocol + typealias Stubbing = __StubbingProxy_YourValidatorListViewProtocol + typealias Verification = __VerificationProxy_YourValidatorListViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsConfirmViewProtocol? + private var __defaultImplStub: YourValidatorListViewProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsConfirmViewProtocol) { + func enableDefaultImplementation(_ stub: YourValidatorListViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -30649,95 +29955,22 @@ import SoraFoundation } - - - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } - - } - - func didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel) { - - return cuckoo_manager.call("didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel)", - parameters: (confirmationViewModel), - escapingParameters: (confirmationViewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(confirmationViewModel: confirmationViewModel)) - - } - - - - func didReceive(hintsViewModel: LocalizableResource<[String]>) { - - return cuckoo_manager.call("didReceive(hintsViewModel: LocalizableResource<[String]>)", - parameters: (hintsViewModel), - escapingParameters: (hintsViewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(hintsViewModel: hintsViewModel)) - - } - - - - func didReceive(amountViewModel: LocalizableResource?) { - - return cuckoo_manager.call("didReceive(amountViewModel: LocalizableResource?)", - parameters: (amountViewModel), - escapingParameters: (amountViewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(amountViewModel: amountViewModel)) - - } - - - - func didReceive(feeViewModel: LocalizableResource?) { + func reload(state: YourValidatorListViewState) { - return cuckoo_manager.call("didReceive(feeViewModel: LocalizableResource?)", - parameters: (feeViewModel), - escapingParameters: (feeViewModel), + return cuckoo_manager.call("reload(state: YourValidatorListViewState)", + parameters: (state), + escapingParameters: (state), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(feeViewModel: feeViewModel)) + defaultCall: __defaultImplStub!.reload(state: state)) } @@ -30756,38 +29989,8 @@ import SoraFoundation } - - - func didStartLoading() { - - return cuckoo_manager.call("didStartLoading()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didStartLoading()) - - } - - - - func didStopLoading() { - - return cuckoo_manager.call("didStopLoading()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didStopLoading()) - - } - - struct __StubbingProxy_SelectValidatorsConfirmViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_YourValidatorListViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -30795,69 +29998,34 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") - } - - - func didReceive(confirmationViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectValidatorsConfirmViewModel)> where M1.MatchedType == SelectValidatorsConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsConfirmViewModel)>] = [wrap(matchable: confirmationViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel)", parameterMatchers: matchers)) - } - - func didReceive(hintsViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource<[String]>)> where M1.MatchedType == LocalizableResource<[String]> { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource<[String]>)>] = [wrap(matchable: hintsViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didReceive(hintsViewModel: LocalizableResource<[String]>)", parameterMatchers: matchers)) - } - - func didReceive(amountViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: amountViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didReceive(amountViewModel: LocalizableResource?)", parameterMatchers: matchers)) - } - - func didReceive(feeViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: feeViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didReceive(feeViewModel: LocalizableResource?)", parameterMatchers: matchers)) + func reload(state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(YourValidatorListViewState)> where M1.MatchedType == YourValidatorListViewState { + let matchers: [Cuckoo.ParameterMatcher<(YourValidatorListViewState)>] = [wrap(matchable: state) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListViewProtocol.self, method: "reload(state: YourValidatorListViewState)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) - } - - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) - } - - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsConfirmViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_YourValidatorListViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -30884,40 +30052,12 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceive(confirmationViewModel: M1) -> Cuckoo.__DoNotUse<(SelectValidatorsConfirmViewModel), Void> where M1.MatchedType == SelectValidatorsConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsConfirmViewModel)>] = [wrap(matchable: confirmationViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(hintsViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource<[String]>), Void> where M1.MatchedType == LocalizableResource<[String]> { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource<[String]>)>] = [wrap(matchable: hintsViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(hintsViewModel: LocalizableResource<[String]>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(amountViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: amountViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(amountViewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(feeViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: feeViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(feeViewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload(state: M1) -> Cuckoo.__DoNotUse<(YourValidatorListViewState), Void> where M1.MatchedType == YourValidatorListViewState { + let matchers: [Cuckoo.ParameterMatcher<(YourValidatorListViewState)>] = [wrap(matchable: state) { $0 }] + return cuckoo_manager.verify("reload(state: YourValidatorListViewState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -30926,22 +30066,10 @@ import SoraFoundation return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } - class SelectValidatorsConfirmViewProtocolStub: SelectValidatorsConfirmViewProtocol { + class YourValidatorListViewProtocolStub: YourValidatorListViewProtocol { @@ -30971,24 +30099,6 @@ import SoraFoundation set { } } - - - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } @@ -30996,25 +30106,7 @@ import SoraFoundation - func didReceive(confirmationViewModel: SelectValidatorsConfirmViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(hintsViewModel: LocalizableResource<[String]>) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(amountViewModel: LocalizableResource?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceive(feeViewModel: LocalizableResource?) { + func reload(state: YourValidatorListViewState) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -31024,35 +30116,23 @@ import SoraFoundation return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - func didStartLoading() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didStopLoading() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - } - class MockSelectValidatorsConfirmPresenterProtocol: SelectValidatorsConfirmPresenterProtocol, Cuckoo.ProtocolMock { + class MockYourValidatorListPresenterProtocol: YourValidatorListPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsConfirmPresenterProtocol + typealias MocksType = YourValidatorListPresenterProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmPresenterProtocol - typealias Verification = __VerificationProxy_SelectValidatorsConfirmPresenterProtocol + typealias Stubbing = __StubbingProxy_YourValidatorListPresenterProtocol + typealias Verification = __VerificationProxy_YourValidatorListPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsConfirmPresenterProtocol? + private var __defaultImplStub: YourValidatorListPresenterProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsConfirmPresenterProtocol) { + func enableDefaultImplementation(_ stub: YourValidatorListPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -31080,51 +30160,51 @@ import SoraFoundation - func selectWalletAccount() { + func retry() { - return cuckoo_manager.call("selectWalletAccount()", + return cuckoo_manager.call("retry()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectWalletAccount()) + defaultCall: __defaultImplStub!.retry()) } - func selectPayoutAccount() { + func didSelectValidator(viewModel: YourValidatorViewModel) { - return cuckoo_manager.call("selectPayoutAccount()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didSelectValidator(viewModel: YourValidatorViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectPayoutAccount()) + defaultCall: __defaultImplStub!.didSelectValidator(viewModel: viewModel)) } - func proceed() { + func changeValidators() { - return cuckoo_manager.call("proceed()", + return cuckoo_manager.call("changeValidators()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.changeValidators()) } - struct __StubbingProxy_SelectValidatorsConfirmPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_YourValidatorListPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -31134,27 +30214,27 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func selectWalletAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func retry() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmPresenterProtocol.self, method: "selectWalletAccount()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListPresenterProtocol.self, method: "retry()", parameterMatchers: matchers)) } - func selectPayoutAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmPresenterProtocol.self, method: "selectPayoutAccount()", parameterMatchers: matchers)) + func didSelectValidator(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(YourValidatorViewModel)> where M1.MatchedType == YourValidatorViewModel { + let matchers: [Cuckoo.ParameterMatcher<(YourValidatorViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListPresenterProtocol.self, method: "didSelectValidator(viewModel: YourValidatorViewModel)", parameterMatchers: matchers)) } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func changeValidators() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListPresenterProtocol.self, method: "changeValidators()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsConfirmPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_YourValidatorListPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -31175,27 +30255,27 @@ import SoraFoundation } @discardableResult - func selectWalletAccount() -> Cuckoo.__DoNotUse<(), Void> { + func retry() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectWalletAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("retry()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectPayoutAccount() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectPayoutAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didSelectValidator(viewModel: M1) -> Cuckoo.__DoNotUse<(YourValidatorViewModel), Void> where M1.MatchedType == YourValidatorViewModel { + let matchers: [Cuckoo.ParameterMatcher<(YourValidatorViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didSelectValidator(viewModel: YourValidatorViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { + func changeValidators() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("changeValidators()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SelectValidatorsConfirmPresenterProtocolStub: SelectValidatorsConfirmPresenterProtocol { + class YourValidatorListPresenterProtocolStub: YourValidatorListPresenterProtocol { @@ -31209,19 +30289,19 @@ import SoraFoundation - func selectWalletAccount() { + func retry() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectPayoutAccount() { + func didSelectValidator(viewModel: YourValidatorViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func proceed() { + func changeValidators() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -31229,19 +30309,19 @@ import SoraFoundation - class MockSelectValidatorsConfirmInteractorInputProtocol: SelectValidatorsConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockYourValidatorListInteractorInputProtocol: YourValidatorListInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsConfirmInteractorInputProtocol + typealias MocksType = YourValidatorListInteractorInputProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmInteractorInputProtocol - typealias Verification = __VerificationProxy_SelectValidatorsConfirmInteractorInputProtocol + typealias Stubbing = __StubbingProxy_YourValidatorListInteractorInputProtocol + typealias Verification = __VerificationProxy_YourValidatorListInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsConfirmInteractorInputProtocol? + private var __defaultImplStub: YourValidatorListInteractorInputProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsConfirmInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: YourValidatorListInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -31269,36 +30349,21 @@ import SoraFoundation - func submitNomination() { - - return cuckoo_manager.call("submitNomination()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.submitNomination()) - - } - - - - func estimateFee() { + func refresh() { - return cuckoo_manager.call("estimateFee()", + return cuckoo_manager.call("refresh()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFee()) + defaultCall: __defaultImplStub!.refresh()) } - struct __StubbingProxy_SelectValidatorsConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_YourValidatorListInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -31308,22 +30373,17 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func submitNomination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorInputProtocol.self, method: "submitNomination()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func refresh() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorInputProtocol.self, method: "refresh()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_YourValidatorListInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -31344,21 +30404,15 @@ import SoraFoundation } @discardableResult - func submitNomination() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("submitNomination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { + func refresh() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("refresh()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SelectValidatorsConfirmInteractorInputProtocolStub: SelectValidatorsConfirmInteractorInputProtocol { + class YourValidatorListInteractorInputProtocolStub: YourValidatorListInteractorInputProtocol { @@ -31372,13 +30426,7 @@ import SoraFoundation - func submitNomination() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func estimateFee() { + func refresh() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -31386,19 +30434,19 @@ import SoraFoundation - class MockSelectValidatorsConfirmInteractorOutputProtocol: SelectValidatorsConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockYourValidatorListInteractorOutputProtocol: YourValidatorListInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsConfirmInteractorOutputProtocol + typealias MocksType = YourValidatorListInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmInteractorOutputProtocol - typealias Verification = __VerificationProxy_SelectValidatorsConfirmInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_YourValidatorListInteractorOutputProtocol + typealias Verification = __VerificationProxy_YourValidatorListInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsConfirmInteractorOutputProtocol? + private var __defaultImplStub: YourValidatorListInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsConfirmInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: YourValidatorListInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -31411,186 +30459,81 @@ import SoraFoundation - func didReceiveModel(result: Result) { + func didReceiveValidators(result: Result) { - return cuckoo_manager.call("didReceiveModel(result: Result)", + return cuckoo_manager.call("didReceiveValidators(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveModel(result: result)) + defaultCall: __defaultImplStub!.didReceiveValidators(result: result)) } - func didReceivePrice(result: Result) { + func didReceiveController(result: Result) { - return cuckoo_manager.call("didReceivePrice(result: Result)", + return cuckoo_manager.call("didReceiveController(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePrice(result: result)) + defaultCall: __defaultImplStub!.didReceiveController(result: result)) } - func didReceiveAccountInfo(result: Result) { + func didReceiveStashItem(result: Result) { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + return cuckoo_manager.call("didReceiveStashItem(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) } - func didReceiveMinBond(result: Result) { + func didReceiveLedger(result: Result) { - return cuckoo_manager.call("didReceiveMinBond(result: Result)", + return cuckoo_manager.call("didReceiveLedger(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMinBond(result: result)) + defaultCall: __defaultImplStub!.didReceiveLedger(result: result)) } - func didReceiveCounterForNominators(result: Result) { + func didReceiveRewardDestination(result: Result) { - return cuckoo_manager.call("didReceiveCounterForNominators(result: Result)", + return cuckoo_manager.call("didReceiveRewardDestination(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveCounterForNominators(result: result)) - - } - - - - func didReceiveMaxNominatorsCount(result: Result) { - - return cuckoo_manager.call("didReceiveMaxNominatorsCount(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveMaxNominatorsCount(result: result)) - - } - - - - func didReceiveStakingDuration(result: Result) { - - return cuckoo_manager.call("didReceiveStakingDuration(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveStakingDuration(result: result)) - - } - - - - func didStartNomination() { - - return cuckoo_manager.call("didStartNomination()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didStartNomination()) - - } - - - - func didCompleteNomination(txHash: String) { - - return cuckoo_manager.call("didCompleteNomination(txHash: String)", - parameters: (txHash), - escapingParameters: (txHash), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didCompleteNomination(txHash: txHash)) - - } - - - - func didFailNomination(error: Error) { - - return cuckoo_manager.call("didFailNomination(error: Error)", - parameters: (error), - escapingParameters: (error), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didFailNomination(error: error)) - - } - - - - func didReceive(paymentInfo: RuntimeDispatchInfo) { - - return cuckoo_manager.call("didReceive(paymentInfo: RuntimeDispatchInfo)", - parameters: (paymentInfo), - escapingParameters: (paymentInfo), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(paymentInfo: paymentInfo)) - - } - - - - func didReceive(feeError: Error) { - - return cuckoo_manager.call("didReceive(feeError: Error)", - parameters: (feeError), - escapingParameters: (feeError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(feeError: feeError)) + defaultCall: __defaultImplStub!.didReceiveRewardDestination(result: result)) } - struct __StubbingProxy_SelectValidatorsConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_YourValidatorListInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -31598,69 +30541,34 @@ import SoraFoundation } - func didReceiveModel(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveModel(result: Result)", parameterMatchers: matchers)) - } - - func didReceivePrice(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceivePrice(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveMinBond(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveMinBond(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveCounterForNominators(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveCounterForNominators(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveMaxNominatorsCount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveMaxNominatorsCount(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveStakingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceiveStakingDuration(result: Result)", parameterMatchers: matchers)) - } - - func didStartNomination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didStartNomination()", parameterMatchers: matchers)) + func didReceiveValidators(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveValidators(result: Result)", parameterMatchers: matchers)) } - func didCompleteNomination(txHash: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: txHash) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didCompleteNomination(txHash: String)", parameterMatchers: matchers)) + func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) } - func didFailNomination(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didFailNomination(error: Error)", parameterMatchers: matchers)) + func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) } - func didReceive(paymentInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RuntimeDispatchInfo)> where M1.MatchedType == RuntimeDispatchInfo { - let matchers: [Cuckoo.ParameterMatcher<(RuntimeDispatchInfo)>] = [wrap(matchable: paymentInfo) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceive(paymentInfo: RuntimeDispatchInfo)", parameterMatchers: matchers)) + func didReceiveLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveLedger(result: Result)", parameterMatchers: matchers)) } - func didReceive(feeError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: feeError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmInteractorOutputProtocol.self, method: "didReceive(feeError: Error)", parameterMatchers: matchers)) + func didReceiveRewardDestination(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveRewardDestination(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_YourValidatorListInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -31675,81 +30583,39 @@ import SoraFoundation @discardableResult - func didReceiveModel(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveModel(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePrice(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePrice(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveMinBond(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMinBond(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveCounterForNominators(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveCounterForNominators(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveMaxNominatorsCount(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMaxNominatorsCount(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveStakingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didStartNomination() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartNomination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveValidators(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveValidators(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didCompleteNomination(txHash: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: txHash) { $0 }] - return cuckoo_manager.verify("didCompleteNomination(txHash: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didFailNomination(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return cuckoo_manager.verify("didFailNomination(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(paymentInfo: M1) -> Cuckoo.__DoNotUse<(RuntimeDispatchInfo), Void> where M1.MatchedType == RuntimeDispatchInfo { - let matchers: [Cuckoo.ParameterMatcher<(RuntimeDispatchInfo)>] = [wrap(matchable: paymentInfo) { $0 }] - return cuckoo_manager.verify("didReceive(paymentInfo: RuntimeDispatchInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(feeError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: feeError) { $0 }] - return cuckoo_manager.verify("didReceive(feeError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveRewardDestination(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveRewardDestination(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SelectValidatorsConfirmInteractorOutputProtocolStub: SelectValidatorsConfirmInteractorOutputProtocol { + class YourValidatorListInteractorOutputProtocolStub: YourValidatorListInteractorOutputProtocol { @@ -31757,73 +30623,31 @@ import SoraFoundation - func didReceiveModel(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceivePrice(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAccountInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveMinBond(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveCounterForNominators(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveMaxNominatorsCount(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveStakingDuration(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didStartNomination() { + func didReceiveValidators(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didCompleteNomination(txHash: String) { + func didReceiveController(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didFailNomination(error: Error) { + func didReceiveStashItem(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(paymentInfo: RuntimeDispatchInfo) { + func didReceiveLedger(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(feeError: Error) { + func didReceiveRewardDestination(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -31831,19 +30655,19 @@ import SoraFoundation - class MockSelectValidatorsConfirmWireframeProtocol: SelectValidatorsConfirmWireframeProtocol, Cuckoo.ProtocolMock { + class MockYourValidatorListWireframeProtocol: YourValidatorListWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsConfirmWireframeProtocol + typealias MocksType = YourValidatorListWireframeProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsConfirmWireframeProtocol - typealias Verification = __VerificationProxy_SelectValidatorsConfirmWireframeProtocol + typealias Stubbing = __StubbingProxy_YourValidatorListWireframeProtocol + typealias Verification = __VerificationProxy_YourValidatorListWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsConfirmWireframeProtocol? + private var __defaultImplStub: YourValidatorListWireframeProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsConfirmWireframeProtocol) { + func enableDefaultImplementation(_ stub: YourValidatorListWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -31856,16 +30680,31 @@ import SoraFoundation - func complete(from view: SelectValidatorsConfirmViewProtocol?) { + func present(_ validatorInfo: ValidatorInfoProtocol, from view: YourValidatorListViewProtocol?) { - return cuckoo_manager.call("complete(from: SelectValidatorsConfirmViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("present(_: ValidatorInfoProtocol, from: YourValidatorListViewProtocol?)", + parameters: (validatorInfo, view), + escapingParameters: (validatorInfo, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.complete(from: view)) + defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) + + } + + + + func proceedToSelectValidatorsStart(from view: YourValidatorListViewProtocol?, existingBonding: ExistingBonding) { + + return cuckoo_manager.call("proceedToSelectValidatorsStart(from: YourValidatorListViewProtocol?, existingBonding: ExistingBonding)", + parameters: (view, existingBonding), + escapingParameters: (view, existingBonding), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.proceedToSelectValidatorsStart(from: view, existingBonding: existingBonding)) } @@ -31900,7 +30739,7 @@ import SoraFoundation } - struct __StubbingProxy_SelectValidatorsConfirmWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_YourValidatorListWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -31908,24 +30747,29 @@ import SoraFoundation } - func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectValidatorsConfirmViewProtocol?)> where M1.OptionalMatchedType == SelectValidatorsConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmWireframeProtocol.self, method: "complete(from: SelectValidatorsConfirmViewProtocol?)", parameterMatchers: matchers)) + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoProtocol, YourValidatorListViewProtocol?)> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == YourValidatorListViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, YourValidatorListViewProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListWireframeProtocol.self, method: "present(_: ValidatorInfoProtocol, from: YourValidatorListViewProtocol?)", parameterMatchers: matchers)) + } + + func proceedToSelectValidatorsStart(from view: M1, existingBonding: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(YourValidatorListViewProtocol?, ExistingBonding)> where M1.OptionalMatchedType == YourValidatorListViewProtocol, M2.MatchedType == ExistingBonding { + let matchers: [Cuckoo.ParameterMatcher<(YourValidatorListViewProtocol?, ExistingBonding)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: existingBonding) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListWireframeProtocol.self, method: "proceedToSelectValidatorsStart(from: YourValidatorListViewProtocol?, existingBonding: ExistingBonding)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsConfirmWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_YourValidatorListWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -31940,9 +30784,15 @@ import SoraFoundation @discardableResult - func complete(from view: M1) -> Cuckoo.__DoNotUse<(SelectValidatorsConfirmViewProtocol?), Void> where M1.OptionalMatchedType == SelectValidatorsConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("complete(from: SelectValidatorsConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(ValidatorInfoProtocol, YourValidatorListViewProtocol?), Void> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == YourValidatorListViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, YourValidatorListViewProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("present(_: ValidatorInfoProtocol, from: YourValidatorListViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func proceedToSelectValidatorsStart(from view: M1, existingBonding: M2) -> Cuckoo.__DoNotUse<(YourValidatorListViewProtocol?, ExistingBonding), Void> where M1.OptionalMatchedType == YourValidatorListViewProtocol, M2.MatchedType == ExistingBonding { + let matchers: [Cuckoo.ParameterMatcher<(YourValidatorListViewProtocol?, ExistingBonding)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: existingBonding) { $0.1 }] + return cuckoo_manager.verify("proceedToSelectValidatorsStart(from: YourValidatorListViewProtocol?, existingBonding: ExistingBonding)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -31960,7 +30810,7 @@ import SoraFoundation } } - class SelectValidatorsConfirmWireframeProtocolStub: SelectValidatorsConfirmWireframeProtocol { + class YourValidatorListWireframeProtocolStub: YourValidatorListWireframeProtocol { @@ -31968,7 +30818,13 @@ import SoraFoundation - func complete(from view: SelectValidatorsConfirmViewProtocol?) { + func present(_ validatorInfo: ValidatorInfoProtocol, from view: YourValidatorListViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func proceedToSelectValidatorsStart(from view: YourValidatorListViewProtocol?, existingBonding: ExistingBonding) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -31990,23 +30846,24 @@ import SoraFoundation import Cuckoo @testable import novawallet -import Foundation +import BigInt +import CommonWallet import SoraFoundation - class MockSelectValidatorsStartViewProtocol: SelectValidatorsStartViewProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMoreViewProtocol: StakingBondMoreViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsStartViewProtocol + typealias MocksType = StakingBondMoreViewProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsStartViewProtocol - typealias Verification = __VerificationProxy_SelectValidatorsStartViewProtocol + typealias Stubbing = __StubbingProxy_StakingBondMoreViewProtocol + typealias Verification = __VerificationProxy_StakingBondMoreViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsStartViewProtocol? + private var __defaultImplStub: StakingBondMoreViewProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsStartViewProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMoreViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -32071,16 +30928,46 @@ import SoraFoundation - func didReceive(viewModel: SelectValidatorsStartViewModel) { + func didReceiveInput(viewModel: LocalizableResource) { - return cuckoo_manager.call("didReceive(viewModel: SelectValidatorsStartViewModel)", + return cuckoo_manager.call("didReceiveInput(viewModel: LocalizableResource)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) + + } + + + + func didReceiveAsset(viewModel: LocalizableResource) { + + return cuckoo_manager.call("didReceiveAsset(viewModel: LocalizableResource)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) + + } + + + + func didReceiveFee(viewModel: LocalizableResource?) { + + return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) } @@ -32100,7 +30987,7 @@ import SoraFoundation } - struct __StubbingProxy_SelectValidatorsStartViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMoreViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -32108,34 +30995,44 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectValidatorsStartViewModel)> where M1.MatchedType == SelectValidatorsStartViewModel { - let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsStartViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartViewProtocol.self, method: "didReceive(viewModel: SelectValidatorsStartViewModel)", parameterMatchers: matchers)) + func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreViewProtocol.self, method: "didReceiveInput(viewModel: LocalizableResource)", parameterMatchers: matchers)) + } + + func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreViewProtocol.self, method: "didReceiveAsset(viewModel: LocalizableResource)", parameterMatchers: matchers)) + } + + func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsStartViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMoreViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -32165,9 +31062,21 @@ import SoraFoundation @discardableResult - func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(SelectValidatorsStartViewModel), Void> where M1.MatchedType == SelectValidatorsStartViewModel { - let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsStartViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceive(viewModel: SelectValidatorsStartViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveInput(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveAsset(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -32179,7 +31088,7 @@ import SoraFoundation } } - class SelectValidatorsStartViewProtocolStub: SelectValidatorsStartViewProtocol { + class StakingBondMoreViewProtocolStub: StakingBondMoreViewProtocol { @@ -32216,7 +31125,19 @@ import SoraFoundation - func didReceive(viewModel: SelectValidatorsStartViewModel) { + func didReceiveInput(viewModel: LocalizableResource) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveAsset(viewModel: LocalizableResource) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveFee(viewModel: LocalizableResource?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -32230,19 +31151,19 @@ import SoraFoundation - class MockSelectValidatorsStartPresenterProtocol: SelectValidatorsStartPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMorePresenterProtocol: StakingBondMorePresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsStartPresenterProtocol + typealias MocksType = StakingBondMorePresenterProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsStartPresenterProtocol - typealias Verification = __VerificationProxy_SelectValidatorsStartPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingBondMorePresenterProtocol + typealias Verification = __VerificationProxy_StakingBondMorePresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsStartPresenterProtocol? + private var __defaultImplStub: StakingBondMorePresenterProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsStartPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMorePresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -32270,66 +31191,51 @@ import SoraFoundation - func updateOnAppearance() { + func handleContinueAction() { - return cuckoo_manager.call("updateOnAppearance()", + return cuckoo_manager.call("handleContinueAction()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.updateOnAppearance()) + defaultCall: __defaultImplStub!.handleContinueAction()) } - func selectRecommendedValidators() { + func updateAmount(_ newValue: Decimal) { - return cuckoo_manager.call("selectRecommendedValidators()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("updateAmount(_: Decimal)", + parameters: (newValue), + escapingParameters: (newValue), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectRecommendedValidators()) + defaultCall: __defaultImplStub!.updateAmount(newValue)) } - func selectCustomValidators() { + func selectAmountPercentage(_ percentage: Float) { - return cuckoo_manager.call("selectCustomValidators()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.selectCustomValidators()) - - } - - - - func selectLearnMore() { - - return cuckoo_manager.call("selectLearnMore()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("selectAmountPercentage(_: Float)", + parameters: (percentage), + escapingParameters: (percentage), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectLearnMore()) + defaultCall: __defaultImplStub!.selectAmountPercentage(percentage)) } - struct __StubbingProxy_SelectValidatorsStartPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMorePresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -32339,32 +31245,27 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func updateOnAppearance() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "updateOnAppearance()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMorePresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func selectRecommendedValidators() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func handleContinueAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "selectRecommendedValidators()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMorePresenterProtocol.self, method: "handleContinueAction()", parameterMatchers: matchers)) } - func selectCustomValidators() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "selectCustomValidators()", parameterMatchers: matchers)) + func updateAmount(_ newValue: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMorePresenterProtocol.self, method: "updateAmount(_: Decimal)", parameterMatchers: matchers)) } - func selectLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartPresenterProtocol.self, method: "selectLearnMore()", parameterMatchers: matchers)) + func selectAmountPercentage(_ percentage: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Float)> where M1.MatchedType == Float { + let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMorePresenterProtocol.self, method: "selectAmountPercentage(_: Float)", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsStartPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMorePresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -32385,33 +31286,27 @@ import SoraFoundation } @discardableResult - func updateOnAppearance() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("updateOnAppearance()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func selectRecommendedValidators() -> Cuckoo.__DoNotUse<(), Void> { + func handleContinueAction() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectRecommendedValidators()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("handleContinueAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectCustomValidators() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectCustomValidators()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func updateAmount(_ newValue: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] + return cuckoo_manager.verify("updateAmount(_: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectLearnMore() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectAmountPercentage(_ percentage: M1) -> Cuckoo.__DoNotUse<(Float), Void> where M1.MatchedType == Float { + let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] + return cuckoo_manager.verify("selectAmountPercentage(_: Float)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SelectValidatorsStartPresenterProtocolStub: SelectValidatorsStartPresenterProtocol { + class StakingBondMorePresenterProtocolStub: StakingBondMorePresenterProtocol { @@ -32425,25 +31320,19 @@ import SoraFoundation - func updateOnAppearance() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func selectRecommendedValidators() { + func handleContinueAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectCustomValidators() { + func updateAmount(_ newValue: Decimal) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectLearnMore() { + func selectAmountPercentage(_ percentage: Float) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -32451,19 +31340,19 @@ import SoraFoundation - class MockSelectValidatorsStartInteractorInputProtocol: SelectValidatorsStartInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMoreInteractorInputProtocol: StakingBondMoreInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsStartInteractorInputProtocol + typealias MocksType = StakingBondMoreInteractorInputProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsStartInteractorInputProtocol - typealias Verification = __VerificationProxy_SelectValidatorsStartInteractorInputProtocol + typealias Stubbing = __StubbingProxy_StakingBondMoreInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingBondMoreInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsStartInteractorInputProtocol? + private var __defaultImplStub: StakingBondMoreInteractorInputProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsStartInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMoreInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -32489,8 +31378,23 @@ import SoraFoundation } + + + func estimateFee() { + + return cuckoo_manager.call("estimateFee()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.estimateFee()) + + } + - struct __StubbingProxy_SelectValidatorsStartInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMoreInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -32500,12 +31404,17 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsStartInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMoreInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -32525,10 +31434,16 @@ import SoraFoundation return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } - class SelectValidatorsStartInteractorInputProtocolStub: SelectValidatorsStartInteractorInputProtocol { + class StakingBondMoreInteractorInputProtocolStub: StakingBondMoreInteractorInputProtocol { @@ -32540,23 +31455,29 @@ import SoraFoundation return DefaultValueRegistry.defaultValue(for: (Void).self) } + + + func estimateFee() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + } - class MockSelectValidatorsStartInteractorOutputProtocol: SelectValidatorsStartInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMoreInteractorOutputProtocol: StakingBondMoreInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsStartInteractorOutputProtocol + typealias MocksType = StakingBondMoreInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsStartInteractorOutputProtocol - typealias Verification = __VerificationProxy_SelectValidatorsStartInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_StakingBondMoreInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingBondMoreInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsStartInteractorOutputProtocol? + private var __defaultImplStub: StakingBondMoreInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsStartInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMoreInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -32569,36 +31490,81 @@ import SoraFoundation - func didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>)", + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveValidators(result: result)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - func didReceiveMaxNominations(result: Result) { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("didReceiveMaxNominations(result: Result)", + return cuckoo_manager.call("didReceivePriceData(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMaxNominations(result: result)) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + + } + + + + func didReceiveFee(result: Result) { + + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + + } + + + + func didReceiveStash(result: Result) { + + return cuckoo_manager.call("didReceiveStash(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveStash(result: result)) + + } + + + + func didReceiveStashItem(result: Result) { + + return cuckoo_manager.call("didReceiveStashItem(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) } - struct __StubbingProxy_SelectValidatorsStartInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMoreInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -32606,19 +31572,34 @@ import SoraFoundation } - func didReceiveValidators(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[ElectedValidatorInfo], Error>)> where M1.MatchedType == Result<[ElectedValidatorInfo], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[ElectedValidatorInfo], Error>)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartInteractorOutputProtocol.self, method: "didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>)", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - func didReceiveMaxNominations(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartInteractorOutputProtocol.self, method: "didReceiveMaxNominations(result: Result)", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveStash(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceiveStash(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsStartInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMoreInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -32633,21 +31614,39 @@ import SoraFoundation @discardableResult - func didReceiveValidators(result: M1) -> Cuckoo.__DoNotUse<(Result<[ElectedValidatorInfo], Error>), Void> where M1.MatchedType == Result<[ElectedValidatorInfo], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[ElectedValidatorInfo], Error>)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveMaxNominations(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMaxNominations(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveStash(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStash(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SelectValidatorsStartInteractorOutputProtocolStub: SelectValidatorsStartInteractorOutputProtocol { + class StakingBondMoreInteractorOutputProtocolStub: StakingBondMoreInteractorOutputProtocol { @@ -32655,13 +31654,31 @@ import SoraFoundation - func didReceiveValidators(result: Result<[ElectedValidatorInfo], Error>) { + func didReceiveAccountInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveMaxNominations(result: Result) { + func didReceivePriceData(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveFee(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveStash(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveStashItem(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -32669,19 +31686,19 @@ import SoraFoundation - class MockSelectValidatorsStartWireframeProtocol: SelectValidatorsStartWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMoreWireframeProtocol: StakingBondMoreWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectValidatorsStartWireframeProtocol + typealias MocksType = StakingBondMoreWireframeProtocol - typealias Stubbing = __StubbingProxy_SelectValidatorsStartWireframeProtocol - typealias Verification = __VerificationProxy_SelectValidatorsStartWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingBondMoreWireframeProtocol + typealias Verification = __VerificationProxy_StakingBondMoreWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectValidatorsStartWireframeProtocol? + private var __defaultImplStub: StakingBondMoreWireframeProtocol? - func enableDefaultImplementation(_ stub: SelectValidatorsStartWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMoreWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -32694,46 +31711,31 @@ import SoraFoundation - func proceedToCustomList(from view: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams) { - - return cuckoo_manager.call("proceedToCustomList(from: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams)", - parameters: (view, selectionValidatorGroups, selectedValidatorList, validatorsSelectionParams), - escapingParameters: (view, selectionValidatorGroups, selectedValidatorList, validatorsSelectionParams), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.proceedToCustomList(from: view, selectionValidatorGroups: selectionValidatorGroups, selectedValidatorList: selectedValidatorList, validatorsSelectionParams: validatorsSelectionParams)) - - } - - - - func proceedToRecommendedList(from view: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int) { + func showConfirmation(from view: ControllerBackedProtocol?, amount: Decimal) { - return cuckoo_manager.call("proceedToRecommendedList(from: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int)", - parameters: (view, validatorList, maxTargets), - escapingParameters: (view, validatorList, maxTargets), + return cuckoo_manager.call("showConfirmation(from: ControllerBackedProtocol?, amount: Decimal)", + parameters: (view, amount), + escapingParameters: (view, amount), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceedToRecommendedList(from: view, validatorList: validatorList, maxTargets: maxTargets)) + defaultCall: __defaultImplStub!.showConfirmation(from: view, amount: amount)) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func close(view: ControllerBackedProtocol?) { - return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", - parameters: (url, view, style), - escapingParameters: (url, view, style), + return cuckoo_manager.call("close(view: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) + defaultCall: __defaultImplStub!.close(view: view)) } @@ -32768,7 +31770,7 @@ import SoraFoundation } - struct __StubbingProxy_SelectValidatorsStartWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMoreWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -32776,34 +31778,29 @@ import SoraFoundation } - func proceedToCustomList(from view: M1, selectionValidatorGroups: M2, selectedValidatorList: M3, validatorsSelectionParams: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, SelectionValidatorGroups, SharedList, ValidatorsSelectionParams)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == SelectionValidatorGroups, M3.MatchedType == SharedList, M4.MatchedType == ValidatorsSelectionParams { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, SelectionValidatorGroups, SharedList, ValidatorsSelectionParams)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: selectionValidatorGroups) { $0.1 }, wrap(matchable: selectedValidatorList) { $0.2 }, wrap(matchable: validatorsSelectionParams) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "proceedToCustomList(from: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams)", parameterMatchers: matchers)) - } - - func proceedToRecommendedList(from view: M1, validatorList: M2, maxTargets: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectValidatorsStartViewProtocol?, [SelectedValidatorInfo], Int)> where M1.OptionalMatchedType == SelectValidatorsStartViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsStartViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: validatorList) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "proceedToRecommendedList(from: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int)", parameterMatchers: matchers)) + func showConfirmation(from view: M1, amount: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, Decimal)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: amount) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreWireframeProtocol.self, method: "showConfirmation(from: ControllerBackedProtocol?, amount: Decimal)", parameterMatchers: matchers)) } - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) + func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreWireframeProtocol.self, method: "close(view: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectValidatorsStartWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectValidatorsStartWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMoreWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -32818,21 +31815,15 @@ import SoraFoundation @discardableResult - func proceedToCustomList(from view: M1, selectionValidatorGroups: M2, selectedValidatorList: M3, validatorsSelectionParams: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, SelectionValidatorGroups, SharedList, ValidatorsSelectionParams), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == SelectionValidatorGroups, M3.MatchedType == SharedList, M4.MatchedType == ValidatorsSelectionParams { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, SelectionValidatorGroups, SharedList, ValidatorsSelectionParams)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: selectionValidatorGroups) { $0.1 }, wrap(matchable: selectedValidatorList) { $0.2 }, wrap(matchable: validatorsSelectionParams) { $0.3 }] - return cuckoo_manager.verify("proceedToCustomList(from: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func proceedToRecommendedList(from view: M1, validatorList: M2, maxTargets: M3) -> Cuckoo.__DoNotUse<(SelectValidatorsStartViewProtocol?, [SelectedValidatorInfo], Int), Void> where M1.OptionalMatchedType == SelectValidatorsStartViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(SelectValidatorsStartViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: validatorList) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] - return cuckoo_manager.verify("proceedToRecommendedList(from: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showConfirmation(from view: M1, amount: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, Decimal), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: amount) { $0.1 }] + return cuckoo_manager.verify("showConfirmation(from: ControllerBackedProtocol?, amount: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func close(view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(view: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -32850,7 +31841,7 @@ import SoraFoundation } } - class SelectValidatorsStartWireframeProtocolStub: SelectValidatorsStartWireframeProtocol { + class StakingBondMoreWireframeProtocolStub: StakingBondMoreWireframeProtocol { @@ -32858,19 +31849,13 @@ import SoraFoundation - func proceedToCustomList(from view: ControllerBackedProtocol?, selectionValidatorGroups: SelectionValidatorGroups, selectedValidatorList: SharedList, validatorsSelectionParams: ValidatorsSelectionParams) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func proceedToRecommendedList(from view: SelectValidatorsStartViewProtocol?, validatorList: [SelectedValidatorInfo], maxTargets: Int) { + func showConfirmation(from view: ControllerBackedProtocol?, amount: Decimal) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func close(view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -32892,22 +31877,24 @@ import SoraFoundation import Cuckoo @testable import novawallet +import BigInt +import CommonWallet import SoraFoundation - class MockSelectedValidatorListViewProtocol: SelectedValidatorListViewProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMoreConfirmationViewProtocol: StakingBondMoreConfirmationViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectedValidatorListViewProtocol + typealias MocksType = StakingBondMoreConfirmationViewProtocol - typealias Stubbing = __StubbingProxy_SelectedValidatorListViewProtocol - typealias Verification = __VerificationProxy_SelectedValidatorListViewProtocol + typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationViewProtocol + typealias Verification = __VerificationProxy_StakingBondMoreConfirmationViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectedValidatorListViewProtocol? + private var __defaultImplStub: StakingBondMoreConfirmationViewProtocol? - func enableDefaultImplementation(_ stub: SelectedValidatorListViewProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -32966,37 +31953,80 @@ import SoraFoundation } + + + var loadableContentView: UIView! { + get { + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) + } + + } + - func didReload(_ viewModel: SelectedValidatorListViewModel) { + func didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel) { - return cuckoo_manager.call("didReload(_: SelectedValidatorListViewModel)", + return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReload(viewModel)) + defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) } - func didChangeViewModel(_ viewModel: SelectedValidatorListViewModel, byRemovingItemAt index: Int) { + func didReceiveAmount(viewModel: LocalizableResource) { - return cuckoo_manager.call("didChangeViewModel(_: SelectedValidatorListViewModel, byRemovingItemAt: Int)", - parameters: (viewModel, index), - escapingParameters: (viewModel, index), + return cuckoo_manager.call("didReceiveAmount(viewModel: LocalizableResource)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didChangeViewModel(viewModel, byRemovingItemAt: index)) + defaultCall: __defaultImplStub!.didReceiveAmount(viewModel: viewModel)) + + } + + + + func didReceiveFee(viewModel: LocalizableResource?) { + + return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) } @@ -33015,8 +32045,38 @@ import SoraFoundation } + + + func didStartLoading() { + + return cuckoo_manager.call("didStartLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStartLoading()) + + } + + + + func didStopLoading() { + + return cuckoo_manager.call("didStopLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStopLoading()) + + } + - struct __StubbingProxy_SelectedValidatorListViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMoreConfirmationViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -33024,39 +32084,64 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - func didReload(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorListViewModel)> where M1.MatchedType == SelectedValidatorListViewModel { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListViewProtocol.self, method: "didReload(_: SelectedValidatorListViewModel)", parameterMatchers: matchers)) + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") } - func didChangeViewModel(_ viewModel: M1, byRemovingItemAt index: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorListViewModel, Int)> where M1.MatchedType == SelectedValidatorListViewModel, M2.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewModel, Int)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: index) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListViewProtocol.self, method: "didChangeViewModel(_: SelectedValidatorListViewModel, byRemovingItemAt: Int)", parameterMatchers: matchers)) + + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") + } + + + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingBondMoreConfirmViewModel)> where M1.MatchedType == StakingBondMoreConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingBondMoreConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel)", parameterMatchers: matchers)) + } + + func didReceiveAmount(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didReceiveAmount(viewModel: LocalizableResource)", parameterMatchers: matchers)) + } + + func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + } + + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + } + + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectedValidatorListViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMoreConfirmationViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -33083,18 +32168,34 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func didReload(_ viewModel: M1) -> Cuckoo.__DoNotUse<(SelectedValidatorListViewModel), Void> where M1.MatchedType == SelectedValidatorListViewModel { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReload(_: SelectedValidatorListViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingBondMoreConfirmViewModel), Void> where M1.MatchedType == StakingBondMoreConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingBondMoreConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didChangeViewModel(_ viewModel: M1, byRemovingItemAt index: M2) -> Cuckoo.__DoNotUse<(SelectedValidatorListViewModel, Int), Void> where M1.MatchedType == SelectedValidatorListViewModel, M2.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewModel, Int)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: index) { $0.1 }] - return cuckoo_manager.verify("didChangeViewModel(_: SelectedValidatorListViewModel, byRemovingItemAt: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAmount(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveAmount(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -33103,10 +32204,22 @@ import SoraFoundation return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } - class SelectedValidatorListViewProtocolStub: SelectedValidatorListViewProtocol { + class StakingBondMoreConfirmationViewProtocolStub: StakingBondMoreConfirmationViewProtocol { @@ -33136,6 +32249,24 @@ import SoraFoundation set { } } + + + + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } @@ -33143,112 +32274,37 @@ import SoraFoundation - func didReload(_ viewModel: SelectedValidatorListViewModel) { + func didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didChangeViewModel(_ viewModel: SelectedValidatorListViewModel, byRemovingItemAt index: Int) { + func didReceiveAmount(viewModel: LocalizableResource) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func didReceiveFee(viewModel: LocalizableResource?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockSelectedValidatorListDelegate: SelectedValidatorListDelegate, Cuckoo.ProtocolMock { - - typealias MocksType = SelectedValidatorListDelegate - typealias Stubbing = __StubbingProxy_SelectedValidatorListDelegate - typealias Verification = __VerificationProxy_SelectedValidatorListDelegate - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: SelectedValidatorListDelegate? - - func enableDefaultImplementation(_ stub: SelectedValidatorListDelegate) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + public func applyLocalization() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - - - - - func didRemove(_ validator: SelectedValidatorInfo) { - - return cuckoo_manager.call("didRemove(_: SelectedValidatorInfo)", - parameters: (validator), - escapingParameters: (validator), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didRemove(validator)) - + func didStartLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - struct __StubbingProxy_SelectedValidatorListDelegate: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func didRemove(_ validator: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorInfo)> where M1.MatchedType == SelectedValidatorInfo { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo)>] = [wrap(matchable: validator) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListDelegate.self, method: "didRemove(_: SelectedValidatorInfo)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_SelectedValidatorListDelegate: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func didRemove(_ validator: M1) -> Cuckoo.__DoNotUse<(SelectedValidatorInfo), Void> where M1.MatchedType == SelectedValidatorInfo { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorInfo)>] = [wrap(matchable: validator) { $0 }] - return cuckoo_manager.verify("didRemove(_: SelectedValidatorInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class SelectedValidatorListDelegateStub: SelectedValidatorListDelegate { - - - - - - func didRemove(_ validator: SelectedValidatorInfo) { + func didStopLoading() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -33256,19 +32312,19 @@ import SoraFoundation - class MockSelectedValidatorListPresenterProtocol: SelectedValidatorListPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMoreConfirmationPresenterProtocol: StakingBondMoreConfirmationPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectedValidatorListPresenterProtocol + typealias MocksType = StakingBondMoreConfirmationPresenterProtocol - typealias Stubbing = __StubbingProxy_SelectedValidatorListPresenterProtocol - typealias Verification = __VerificationProxy_SelectedValidatorListPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationPresenterProtocol + typealias Verification = __VerificationProxy_StakingBondMoreConfirmationPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectedValidatorListPresenterProtocol? + private var __defaultImplStub: StakingBondMoreConfirmationPresenterProtocol? - func enableDefaultImplementation(_ stub: SelectedValidatorListPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -33296,66 +32352,36 @@ import SoraFoundation - func didSelectValidator(at index: Int) { - - return cuckoo_manager.call("didSelectValidator(at: Int)", - parameters: (index), - escapingParameters: (index), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didSelectValidator(at: index)) - - } - - - - func removeItem(at index: Int) { - - return cuckoo_manager.call("removeItem(at: Int)", - parameters: (index), - escapingParameters: (index), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.removeItem(at: index)) - - } - - - - func proceed() { + func confirm() { - return cuckoo_manager.call("proceed()", + return cuckoo_manager.call("confirm()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.confirm()) } - func dismiss() { + func selectAccount() { - return cuckoo_manager.call("dismiss()", + return cuckoo_manager.call("selectAccount()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.dismiss()) + defaultCall: __defaultImplStub!.selectAccount()) } - struct __StubbingProxy_SelectedValidatorListPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMoreConfirmationPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -33365,32 +32391,22 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func didSelectValidator(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "didSelectValidator(at: Int)", parameterMatchers: matchers)) - } - - func removeItem(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "removeItem(at: Int)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) } - func dismiss() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func selectAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListPresenterProtocol.self, method: "dismiss()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationPresenterProtocol.self, method: "selectAccount()", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectedValidatorListPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMoreConfirmationPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -33411,33 +32427,21 @@ import SoraFoundation } @discardableResult - func didSelectValidator(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("didSelectValidator(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func removeItem(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("removeItem(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { + func confirm() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func dismiss() -> Cuckoo.__DoNotUse<(), Void> { + func selectAccount() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("dismiss()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("selectAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SelectedValidatorListPresenterProtocolStub: SelectedValidatorListPresenterProtocol { + class StakingBondMoreConfirmationPresenterProtocolStub: StakingBondMoreConfirmationPresenterProtocol { @@ -33451,25 +32455,13 @@ import SoraFoundation - func didSelectValidator(at index: Int) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func removeItem(at index: Int) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func proceed() { + func confirm() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func dismiss() { + func selectAccount() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -33477,19 +32469,19 @@ import SoraFoundation - class MockSelectedValidatorListViewModelFactoryProtocol: SelectedValidatorListViewModelFactoryProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMoreConfirmationInteractorInputProtocol: StakingBondMoreConfirmationInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectedValidatorListViewModelFactoryProtocol + typealias MocksType = StakingBondMoreConfirmationInteractorInputProtocol - typealias Stubbing = __StubbingProxy_SelectedValidatorListViewModelFactoryProtocol - typealias Verification = __VerificationProxy_SelectedValidatorListViewModelFactoryProtocol + typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingBondMoreConfirmationInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectedValidatorListViewModelFactoryProtocol? + private var __defaultImplStub: StakingBondMoreConfirmationInteractorInputProtocol? - func enableDefaultImplementation(_ stub: SelectedValidatorListViewModelFactoryProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -33502,21 +32494,51 @@ import SoraFoundation - func createViewModel(from validatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel { + func setup() { - return cuckoo_manager.call("createViewModel(from: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel", - parameters: (validatorList, totalValidatorsCount, locale), - escapingParameters: (validatorList, totalValidatorsCount, locale), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.createViewModel(from: validatorList, totalValidatorsCount: totalValidatorsCount, locale: locale)) + defaultCall: __defaultImplStub!.setup()) + + } + + + + func submit(for amount: Decimal) { + + return cuckoo_manager.call("submit(for: Decimal)", + parameters: (amount), + escapingParameters: (amount), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.submit(for: amount)) + + } + + + + func estimateFee(for amount: Decimal) { + + return cuckoo_manager.call("estimateFee(for: Decimal)", + parameters: (amount), + escapingParameters: (amount), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.estimateFee(for: amount)) } - struct __StubbingProxy_SelectedValidatorListViewModelFactoryProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMoreConfirmationInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -33524,14 +32546,24 @@ import SoraFoundation } - func createViewModel(from validatorList: M1, totalValidatorsCount: M2, locale: M3) -> Cuckoo.ProtocolStubFunction<([SelectedValidatorInfo], Int, Locale), SelectedValidatorListViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == Int, M3.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], Int, Locale)>] = [wrap(matchable: validatorList) { $0.0 }, wrap(matchable: totalValidatorsCount) { $0.1 }, wrap(matchable: locale) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListViewModelFactoryProtocol.self, method: "createViewModel(from: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func submit(for amount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationInteractorInputProtocol.self, method: "submit(for: Decimal)", parameterMatchers: matchers)) + } + + func estimateFee(for amount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationInteractorInputProtocol.self, method: "estimateFee(for: Decimal)", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectedValidatorListViewModelFactoryProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMoreConfirmationInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -33546,15 +32578,27 @@ import SoraFoundation @discardableResult - func createViewModel(from validatorList: M1, totalValidatorsCount: M2, locale: M3) -> Cuckoo.__DoNotUse<([SelectedValidatorInfo], Int, Locale), SelectedValidatorListViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == Int, M3.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], Int, Locale)>] = [wrap(matchable: validatorList) { $0.0 }, wrap(matchable: totalValidatorsCount) { $0.1 }, wrap(matchable: locale) { $0.2 }] - return cuckoo_manager.verify("createViewModel(from: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func submit(for amount: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] + return cuckoo_manager.verify("submit(for: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func estimateFee(for amount: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] + return cuckoo_manager.verify("estimateFee(for: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SelectedValidatorListViewModelFactoryProtocolStub: SelectedValidatorListViewModelFactoryProtocol { + class StakingBondMoreConfirmationInteractorInputProtocolStub: StakingBondMoreConfirmationInteractorInputProtocol { @@ -33562,27 +32606,39 @@ import SoraFoundation - func createViewModel(from validatorList: [SelectedValidatorInfo], totalValidatorsCount: Int, locale: Locale) -> SelectedValidatorListViewModel { - return DefaultValueRegistry.defaultValue(for: (SelectedValidatorListViewModel).self) + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func submit(for amount: Decimal) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func estimateFee(for amount: Decimal) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } } - class MockSelectedValidatorListWireframeProtocol: SelectedValidatorListWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMoreConfirmationOutputProtocol: StakingBondMoreConfirmationOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = SelectedValidatorListWireframeProtocol + typealias MocksType = StakingBondMoreConfirmationOutputProtocol - typealias Stubbing = __StubbingProxy_SelectedValidatorListWireframeProtocol - typealias Verification = __VerificationProxy_SelectedValidatorListWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationOutputProtocol + typealias Verification = __VerificationProxy_StakingBondMoreConfirmationOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: SelectedValidatorListWireframeProtocol? + private var __defaultImplStub: StakingBondMoreConfirmationOutputProtocol? - func enableDefaultImplementation(_ stub: SelectedValidatorListWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -33595,81 +32651,96 @@ import SoraFoundation - func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", - parameters: (validatorInfo, view), - escapingParameters: (validatorInfo, view), + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - func proceed(from view: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int) { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("proceed(from: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", - parameters: (view, targets, maxTargets), - escapingParameters: (view, targets, maxTargets), + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed(from: view, targets: targets, maxTargets: maxTargets)) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - func dismiss(_ view: ControllerBackedProtocol?) { + func didReceiveFee(result: Result) { - return cuckoo_manager.call("dismiss(_: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.dismiss(view)) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func didReceiveStash(result: Result) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("didReceiveStash(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.didReceiveStash(result: result)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didReceiveStashItem(result: Result) { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("didReceiveStashItem(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) + + } + + + + func didSubmitBonding(result: Result) { + + return cuckoo_manager.call("didSubmitBonding(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didSubmitBonding(result: result)) } - struct __StubbingProxy_SelectedValidatorListWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMoreConfirmationOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -33677,34 +32748,39 @@ import SoraFoundation } - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoProtocol, ControllerBackedProtocol?)> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - func proceed(from view: M1, targets: M2, maxTargets: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(SelectedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)> where M1.OptionalMatchedType == SelectedValidatorListViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: targets) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "proceed(from: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) } - func dismiss(_ view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "dismiss(_: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveStash(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceiveStash(result: Result)", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockSelectedValidatorListWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + } + + func didSubmitBonding(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didSubmitBonding(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_SelectedValidatorListWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMoreConfirmationOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -33719,39 +32795,45 @@ import SoraFoundation @discardableResult - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(ValidatorInfoProtocol, ControllerBackedProtocol?), Void> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceed(from view: M1, targets: M2, maxTargets: M3) -> Cuckoo.__DoNotUse<(SelectedValidatorListViewProtocol?, [SelectedValidatorInfo], Int), Void> where M1.OptionalMatchedType == SelectedValidatorListViewProtocol, M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(SelectedValidatorListViewProtocol?, [SelectedValidatorInfo], Int)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: targets) { $0.1 }, wrap(matchable: maxTargets) { $0.2 }] - return cuckoo_manager.verify("proceed(from: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func dismiss(_ view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("dismiss(_: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStash(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStash(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didSubmitBonding(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didSubmitBonding(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class SelectedValidatorListWireframeProtocolStub: SelectedValidatorListWireframeProtocol { + class StakingBondMoreConfirmationOutputProtocolStub: StakingBondMoreConfirmationOutputProtocol { @@ -33759,153 +32841,114 @@ import SoraFoundation - func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { + func didReceiveAccountInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func proceed(from view: SelectedValidatorListViewProtocol?, targets: [SelectedValidatorInfo], maxTargets: Int) { + func didReceivePriceData(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func dismiss(_ view: ControllerBackedProtocol?) { + func didReceiveFee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func didReceiveStash(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didReceiveStashItem(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didSubmitBonding(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import Foundation -import SoraFoundation - - class MockValidatorStakeInfoProtocol: ValidatorStakeInfoProtocol, Cuckoo.ProtocolMock { + class MockStakingBondMoreConfirmationWireframeProtocol: StakingBondMoreConfirmationWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorStakeInfoProtocol + typealias MocksType = StakingBondMoreConfirmationWireframeProtocol - typealias Stubbing = __StubbingProxy_ValidatorStakeInfoProtocol - typealias Verification = __VerificationProxy_ValidatorStakeInfoProtocol + typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationWireframeProtocol + typealias Verification = __VerificationProxy_StakingBondMoreConfirmationWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorStakeInfoProtocol? + private var __defaultImplStub: StakingBondMoreConfirmationWireframeProtocol? - func enableDefaultImplementation(_ stub: ValidatorStakeInfoProtocol) { + func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + - - var nominators: [NominatorInfo] { - get { - return cuckoo_manager.getter("nominators", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.nominators) - } - - } + - var totalStake: Decimal { - get { - return cuckoo_manager.getter("totalStake", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.totalStake) - } + func complete(from view: StakingBondMoreConfirmationViewProtocol?) { - } - - - - var ownStake: Decimal { - get { - return cuckoo_manager.getter("ownStake", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.ownStake) - } + return cuckoo_manager.call("complete(from: StakingBondMoreConfirmationViewProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.complete(from: view)) } - var stakeReturn: Decimal { - get { - return cuckoo_manager.getter("stakeReturn", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.stakeReturn) - } + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - } - - - - var maxNominatorsRewarded: UInt32 { - get { - return cuckoo_manager.getter("maxNominatorsRewarded", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.maxNominatorsRewarded) - } + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - var oversubscribed: Bool { - get { - return cuckoo_manager.getter("oversubscribed", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.oversubscribed) - } + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - - - - - struct __StubbingProxy_ValidatorStakeInfoProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingBondMoreConfirmationWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -33913,39 +32956,24 @@ import SoraFoundation } - var nominators: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "nominators") - } - - - var totalStake: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "totalStake") - } - - - var ownStake: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "ownStake") - } - - - var stakeReturn: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "stakeReturn") + func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingBondMoreConfirmationViewProtocol?)> where M1.OptionalMatchedType == StakingBondMoreConfirmationViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingBondMoreConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationWireframeProtocol.self, method: "complete(from: StakingBondMoreConfirmationViewProtocol?)", parameterMatchers: matchers)) } - - var maxNominatorsRewarded: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "maxNominatorsRewarded") + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - - var oversubscribed: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "oversubscribed") + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - } - struct __VerificationProxy_ValidatorStakeInfoProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingBondMoreConfirmationWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -33957,242 +32985,646 @@ import SoraFoundation } + - var nominators: Cuckoo.VerifyReadOnlyProperty<[NominatorInfo]> { - return .init(manager: cuckoo_manager, name: "nominators", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var totalStake: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "totalStake", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var ownStake: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "ownStake", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var stakeReturn: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "stakeReturn", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingBondMoreConfirmationViewProtocol?), Void> where M1.OptionalMatchedType == StakingBondMoreConfirmationViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingBondMoreConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("complete(from: StakingBondMoreConfirmationViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var maxNominatorsRewarded: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "maxNominatorsRewarded", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var oversubscribed: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "oversubscribed", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - } } - class ValidatorStakeInfoProtocolStub: ValidatorStakeInfoProtocol { - + class StakingBondMoreConfirmationWireframeProtocolStub: StakingBondMoreConfirmationWireframeProtocol { + - var nominators: [NominatorInfo] { - get { - return DefaultValueRegistry.defaultValue(for: ([NominatorInfo]).self) - } - - } - + - var totalStake: Decimal { - get { - return DefaultValueRegistry.defaultValue(for: (Decimal).self) - } - + + func complete(from view: StakingBondMoreConfirmationViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var ownStake: Decimal { - get { - return DefaultValueRegistry.defaultValue(for: (Decimal).self) - } - + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var stakeReturn: Decimal { - get { - return DefaultValueRegistry.defaultValue(for: (Decimal).self) - } - + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - +} + + +import Cuckoo +@testable import novawallet + +import BigInt +import Foundation + + + class MockStakingRelaychainInteractorInputProtocol: StakingRelaychainInteractorInputProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = StakingRelaychainInteractorInputProtocol - var maxNominatorsRewarded: UInt32 { - get { - return DefaultValueRegistry.defaultValue(for: (UInt32).self) - } - + typealias Stubbing = __StubbingProxy_StakingRelaychainInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingRelaychainInteractorInputProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: StakingRelaychainInteractorInputProtocol? + + func enableDefaultImplementation(_ stub: StakingRelaychainInteractorInputProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } - + + + - var oversubscribed: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } + + + + + func setup() { + + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.setup()) } + struct __StubbingProxy_StakingRelaychainInteractorInputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_StakingRelaychainInteractorInputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class StakingRelaychainInteractorInputProtocolStub: StakingRelaychainInteractorInputProtocol { + + + + + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + } - class MockValidatorInfoProtocol: ValidatorInfoProtocol, Cuckoo.ProtocolMock { + class MockStakingRelaychainInteractorOutputProtocol: StakingRelaychainInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorInfoProtocol + typealias MocksType = StakingRelaychainInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_ValidatorInfoProtocol - typealias Verification = __VerificationProxy_ValidatorInfoProtocol + typealias Stubbing = __StubbingProxy_StakingRelaychainInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingRelaychainInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorInfoProtocol? + private var __defaultImplStub: StakingRelaychainInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: ValidatorInfoProtocol) { + func enableDefaultImplementation(_ stub: StakingRelaychainInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + - var address: String { - get { - return cuckoo_manager.getter("address", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.address) - } + + + func didReceive(selectedAddress: String) { + + return cuckoo_manager.call("didReceive(selectedAddress: String)", + parameters: (selectedAddress), + escapingParameters: (selectedAddress), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(selectedAddress: selectedAddress)) } - var identity: AccountIdentity? { - get { - return cuckoo_manager.getter("identity", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.identity) - } + func didReceive(price: PriceData?) { + + return cuckoo_manager.call("didReceive(price: PriceData?)", + parameters: (price), + escapingParameters: (price), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(price: price)) } - var stakeInfo: ValidatorStakeInfoProtocol? { - get { - return cuckoo_manager.getter("stakeInfo", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.stakeInfo) - } + func didReceive(priceError: Error) { + + return cuckoo_manager.call("didReceive(priceError: Error)", + parameters: (priceError), + escapingParameters: (priceError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(priceError: priceError)) } - var myNomination: ValidatorMyNominationStatus? { - get { - return cuckoo_manager.getter("myNomination", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.myNomination) - } + func didReceive(totalReward: TotalRewardItem) { + + return cuckoo_manager.call("didReceive(totalReward: TotalRewardItem)", + parameters: (totalReward), + escapingParameters: (totalReward), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(totalReward: totalReward)) } - var totalStake: Decimal { - get { - return cuckoo_manager.getter("totalStake", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.totalStake) - } + func didReceive(totalRewardError: Error) { + + return cuckoo_manager.call("didReceive(totalRewardError: Error)", + parameters: (totalRewardError), + escapingParameters: (totalRewardError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(totalRewardError: totalRewardError)) } - var ownStake: Decimal { - get { - return cuckoo_manager.getter("ownStake", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.ownStake) - } + func didReceive(accountInfo: AccountInfo?) { + + return cuckoo_manager.call("didReceive(accountInfo: AccountInfo?)", + parameters: (accountInfo), + escapingParameters: (accountInfo), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(accountInfo: accountInfo)) } - var hasSlashes: Bool { - get { - return cuckoo_manager.getter("hasSlashes", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.hasSlashes) - } + func didReceive(balanceError: Error) { + + return cuckoo_manager.call("didReceive(balanceError: Error)", + parameters: (balanceError), + escapingParameters: (balanceError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(balanceError: balanceError)) } - var blocked: Bool { - get { - return cuckoo_manager.getter("blocked", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.blocked) - } + func didReceive(calculator: RewardCalculatorEngineProtocol) { + + return cuckoo_manager.call("didReceive(calculator: RewardCalculatorEngineProtocol)", + parameters: (calculator), + escapingParameters: (calculator), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(calculator: calculator)) } - - + + func didReceive(calculatorError: Error) { + + return cuckoo_manager.call("didReceive(calculatorError: Error)", + parameters: (calculatorError), + escapingParameters: (calculatorError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(calculatorError: calculatorError)) + + } + + + + func didReceive(stashItem: StashItem?) { + + return cuckoo_manager.call("didReceive(stashItem: StashItem?)", + parameters: (stashItem), + escapingParameters: (stashItem), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(stashItem: stashItem)) + + } + + + + func didReceive(stashItemError: Error) { + + return cuckoo_manager.call("didReceive(stashItemError: Error)", + parameters: (stashItemError), + escapingParameters: (stashItemError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(stashItemError: stashItemError)) + + } + + + + func didReceive(ledgerInfo: StakingLedger?) { + + return cuckoo_manager.call("didReceive(ledgerInfo: StakingLedger?)", + parameters: (ledgerInfo), + escapingParameters: (ledgerInfo), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(ledgerInfo: ledgerInfo)) + + } + + + + func didReceive(ledgerInfoError: Error) { + + return cuckoo_manager.call("didReceive(ledgerInfoError: Error)", + parameters: (ledgerInfoError), + escapingParameters: (ledgerInfoError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(ledgerInfoError: ledgerInfoError)) + + } + + + + func didReceive(nomination: Nomination?) { + + return cuckoo_manager.call("didReceive(nomination: Nomination?)", + parameters: (nomination), + escapingParameters: (nomination), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(nomination: nomination)) + + } + + + + func didReceive(nominationError: Error) { + + return cuckoo_manager.call("didReceive(nominationError: Error)", + parameters: (nominationError), + escapingParameters: (nominationError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(nominationError: nominationError)) + + } + + + + func didReceive(validatorPrefs: ValidatorPrefs?) { + + return cuckoo_manager.call("didReceive(validatorPrefs: ValidatorPrefs?)", + parameters: (validatorPrefs), + escapingParameters: (validatorPrefs), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(validatorPrefs: validatorPrefs)) + + } + + + + func didReceive(validatorError: Error) { + + return cuckoo_manager.call("didReceive(validatorError: Error)", + parameters: (validatorError), + escapingParameters: (validatorError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(validatorError: validatorError)) + + } + + + + func didReceive(eraStakersInfo: EraStakersInfo) { + + return cuckoo_manager.call("didReceive(eraStakersInfo: EraStakersInfo)", + parameters: (eraStakersInfo), + escapingParameters: (eraStakersInfo), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(eraStakersInfo: eraStakersInfo)) + + } + + + + func didReceive(eraStakersInfoError: Error) { + + return cuckoo_manager.call("didReceive(eraStakersInfoError: Error)", + parameters: (eraStakersInfoError), + escapingParameters: (eraStakersInfoError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(eraStakersInfoError: eraStakersInfoError)) + + } + + + + func didReceive(networkStakingInfo: NetworkStakingInfo) { + + return cuckoo_manager.call("didReceive(networkStakingInfo: NetworkStakingInfo)", + parameters: (networkStakingInfo), + escapingParameters: (networkStakingInfo), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(networkStakingInfo: networkStakingInfo)) + + } + + + + func didReceive(networkStakingInfoError: Error) { + + return cuckoo_manager.call("didReceive(networkStakingInfoError: Error)", + parameters: (networkStakingInfoError), + escapingParameters: (networkStakingInfoError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(networkStakingInfoError: networkStakingInfoError)) + + } + + + + func didReceive(payee: RewardDestinationArg?) { + + return cuckoo_manager.call("didReceive(payee: RewardDestinationArg?)", + parameters: (payee), + escapingParameters: (payee), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(payee: payee)) + + } + + + + func didReceive(payeeError: Error) { + + return cuckoo_manager.call("didReceive(payeeError: Error)", + parameters: (payeeError), + escapingParameters: (payeeError), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(payeeError: payeeError)) + + } + + + + func didReceive(newChainAsset: ChainAsset) { + + return cuckoo_manager.call("didReceive(newChainAsset: ChainAsset)", + parameters: (newChainAsset), + escapingParameters: (newChainAsset), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(newChainAsset: newChainAsset)) + + } + + + + func didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod) { + + return cuckoo_manager.call("didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod)", + parameters: (subqueryRewards, period), + escapingParameters: (subqueryRewards, period), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceieve(subqueryRewards: subqueryRewards, period: period)) + + } + + + + func didReceiveMinNominatorBond(result: Result) { + + return cuckoo_manager.call("didReceiveMinNominatorBond(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveMinNominatorBond(result: result)) + + } + + + + func didReceiveCounterForNominators(result: Result) { + + return cuckoo_manager.call("didReceiveCounterForNominators(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveCounterForNominators(result: result)) + + } + + + + func didReceiveMaxNominatorsCount(result: Result) { + + return cuckoo_manager.call("didReceiveMaxNominatorsCount(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveMaxNominatorsCount(result: result)) + + } + + + + func didReceive(eraCountdownResult: Result) { + + return cuckoo_manager.call("didReceive(eraCountdownResult: Result)", + parameters: (eraCountdownResult), + escapingParameters: (eraCountdownResult), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(eraCountdownResult: eraCountdownResult)) + + } + + + + func didReceiveMaxNominatorsPerValidator(result: Result) { + + return cuckoo_manager.call("didReceiveMaxNominatorsPerValidator(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveMaxNominatorsPerValidator(result: result)) + + } + + + + func didReceiveAccount(_ account: MetaChainAccountResponse?, for accountId: AccountId) { + + return cuckoo_manager.call("didReceiveAccount(_: MetaChainAccountResponse?, for: AccountId)", + parameters: (account, accountId), + escapingParameters: (account, accountId), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveAccount(account, for: accountId)) + + } - struct __StubbingProxy_ValidatorInfoProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRelaychainInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -34200,698 +33632,555 @@ import SoraFoundation } - var address: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "address") + func didReceive(selectedAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: selectedAddress) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(selectedAddress: String)", parameterMatchers: matchers)) } + func didReceive(price: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PriceData?)> where M1.OptionalMatchedType == PriceData { + let matchers: [Cuckoo.ParameterMatcher<(PriceData?)>] = [wrap(matchable: price) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(price: PriceData?)", parameterMatchers: matchers)) + } - var identity: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "identity") + func didReceive(priceError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: priceError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(priceError: Error)", parameterMatchers: matchers)) } + func didReceive(totalReward: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(TotalRewardItem)> where M1.MatchedType == TotalRewardItem { + let matchers: [Cuckoo.ParameterMatcher<(TotalRewardItem)>] = [wrap(matchable: totalReward) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(totalReward: TotalRewardItem)", parameterMatchers: matchers)) + } - var stakeInfo: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "stakeInfo") + func didReceive(totalRewardError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: totalRewardError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(totalRewardError: Error)", parameterMatchers: matchers)) } + func didReceive(accountInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountInfo?)> where M1.OptionalMatchedType == AccountInfo { + let matchers: [Cuckoo.ParameterMatcher<(AccountInfo?)>] = [wrap(matchable: accountInfo) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(accountInfo: AccountInfo?)", parameterMatchers: matchers)) + } - var myNomination: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "myNomination") + func didReceive(balanceError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: balanceError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(balanceError: Error)", parameterMatchers: matchers)) + } + + func didReceive(calculator: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RewardCalculatorEngineProtocol)> where M1.MatchedType == RewardCalculatorEngineProtocol { + let matchers: [Cuckoo.ParameterMatcher<(RewardCalculatorEngineProtocol)>] = [wrap(matchable: calculator) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(calculator: RewardCalculatorEngineProtocol)", parameterMatchers: matchers)) + } + + func didReceive(calculatorError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: calculatorError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(calculatorError: Error)", parameterMatchers: matchers)) + } + + func didReceive(stashItem: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StashItem?)> where M1.OptionalMatchedType == StashItem { + let matchers: [Cuckoo.ParameterMatcher<(StashItem?)>] = [wrap(matchable: stashItem) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(stashItem: StashItem?)", parameterMatchers: matchers)) + } + + func didReceive(stashItemError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: stashItemError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(stashItemError: Error)", parameterMatchers: matchers)) + } + + func didReceive(ledgerInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingLedger?)> where M1.OptionalMatchedType == StakingLedger { + let matchers: [Cuckoo.ParameterMatcher<(StakingLedger?)>] = [wrap(matchable: ledgerInfo) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(ledgerInfo: StakingLedger?)", parameterMatchers: matchers)) + } + + func didReceive(ledgerInfoError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: ledgerInfoError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(ledgerInfoError: Error)", parameterMatchers: matchers)) + } + + func didReceive(nomination: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Nomination?)> where M1.OptionalMatchedType == Nomination { + let matchers: [Cuckoo.ParameterMatcher<(Nomination?)>] = [wrap(matchable: nomination) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(nomination: Nomination?)", parameterMatchers: matchers)) + } + + func didReceive(nominationError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: nominationError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(nominationError: Error)", parameterMatchers: matchers)) + } + + func didReceive(validatorPrefs: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorPrefs?)> where M1.OptionalMatchedType == ValidatorPrefs { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorPrefs?)>] = [wrap(matchable: validatorPrefs) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(validatorPrefs: ValidatorPrefs?)", parameterMatchers: matchers)) + } + + func didReceive(validatorError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: validatorError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(validatorError: Error)", parameterMatchers: matchers)) + } + + func didReceive(eraStakersInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(EraStakersInfo)> where M1.MatchedType == EraStakersInfo { + let matchers: [Cuckoo.ParameterMatcher<(EraStakersInfo)>] = [wrap(matchable: eraStakersInfo) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(eraStakersInfo: EraStakersInfo)", parameterMatchers: matchers)) + } + + func didReceive(eraStakersInfoError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: eraStakersInfoError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(eraStakersInfoError: Error)", parameterMatchers: matchers)) + } + + func didReceive(networkStakingInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(NetworkStakingInfo)> where M1.MatchedType == NetworkStakingInfo { + let matchers: [Cuckoo.ParameterMatcher<(NetworkStakingInfo)>] = [wrap(matchable: networkStakingInfo) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(networkStakingInfo: NetworkStakingInfo)", parameterMatchers: matchers)) + } + + func didReceive(networkStakingInfoError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: networkStakingInfoError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(networkStakingInfoError: Error)", parameterMatchers: matchers)) + } + + func didReceive(payee: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RewardDestinationArg?)> where M1.OptionalMatchedType == RewardDestinationArg { + let matchers: [Cuckoo.ParameterMatcher<(RewardDestinationArg?)>] = [wrap(matchable: payee) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(payee: RewardDestinationArg?)", parameterMatchers: matchers)) + } + + func didReceive(payeeError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: payeeError) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(payeeError: Error)", parameterMatchers: matchers)) + } + + func didReceive(newChainAsset: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainAsset)> where M1.MatchedType == ChainAsset { + let matchers: [Cuckoo.ParameterMatcher<(ChainAsset)>] = [wrap(matchable: newChainAsset) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(newChainAsset: ChainAsset)", parameterMatchers: matchers)) + } + + func didReceieve(subqueryRewards: M1, period: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[SubqueryRewardItemData]?, Error>, AnalyticsPeriod)> where M1.MatchedType == Result<[SubqueryRewardItemData]?, Error>, M2.MatchedType == AnalyticsPeriod { + let matchers: [Cuckoo.ParameterMatcher<(Result<[SubqueryRewardItemData]?, Error>, AnalyticsPeriod)>] = [wrap(matchable: subqueryRewards) { $0.0 }, wrap(matchable: period) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod)", parameterMatchers: matchers)) + } + + func didReceiveMinNominatorBond(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveMinNominatorBond(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveCounterForNominators(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveCounterForNominators(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveMaxNominatorsCount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveMaxNominatorsCount(result: Result)", parameterMatchers: matchers)) + } + + func didReceive(eraCountdownResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: eraCountdownResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(eraCountdownResult: Result)", parameterMatchers: matchers)) + } + + func didReceiveMaxNominatorsPerValidator(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveMaxNominatorsPerValidator(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveAccount(_ account: M1, for accountId: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(MetaChainAccountResponse?, AccountId)> where M1.OptionalMatchedType == MetaChainAccountResponse, M2.MatchedType == AccountId { + let matchers: [Cuckoo.ParameterMatcher<(MetaChainAccountResponse?, AccountId)>] = [wrap(matchable: account) { $0.0 }, wrap(matchable: accountId) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveAccount(_: MetaChainAccountResponse?, for: AccountId)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_StakingRelaychainInteractorOutputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func didReceive(selectedAddress: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: selectedAddress) { $0 }] + return cuckoo_manager.verify("didReceive(selectedAddress: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(price: M1) -> Cuckoo.__DoNotUse<(PriceData?), Void> where M1.OptionalMatchedType == PriceData { + let matchers: [Cuckoo.ParameterMatcher<(PriceData?)>] = [wrap(matchable: price) { $0 }] + return cuckoo_manager.verify("didReceive(price: PriceData?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(priceError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: priceError) { $0 }] + return cuckoo_manager.verify("didReceive(priceError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(totalReward: M1) -> Cuckoo.__DoNotUse<(TotalRewardItem), Void> where M1.MatchedType == TotalRewardItem { + let matchers: [Cuckoo.ParameterMatcher<(TotalRewardItem)>] = [wrap(matchable: totalReward) { $0 }] + return cuckoo_manager.verify("didReceive(totalReward: TotalRewardItem)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(totalRewardError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: totalRewardError) { $0 }] + return cuckoo_manager.verify("didReceive(totalRewardError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(accountInfo: M1) -> Cuckoo.__DoNotUse<(AccountInfo?), Void> where M1.OptionalMatchedType == AccountInfo { + let matchers: [Cuckoo.ParameterMatcher<(AccountInfo?)>] = [wrap(matchable: accountInfo) { $0 }] + return cuckoo_manager.verify("didReceive(accountInfo: AccountInfo?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(balanceError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: balanceError) { $0 }] + return cuckoo_manager.verify("didReceive(balanceError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(calculator: M1) -> Cuckoo.__DoNotUse<(RewardCalculatorEngineProtocol), Void> where M1.MatchedType == RewardCalculatorEngineProtocol { + let matchers: [Cuckoo.ParameterMatcher<(RewardCalculatorEngineProtocol)>] = [wrap(matchable: calculator) { $0 }] + return cuckoo_manager.verify("didReceive(calculator: RewardCalculatorEngineProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(calculatorError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: calculatorError) { $0 }] + return cuckoo_manager.verify("didReceive(calculatorError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(stashItem: M1) -> Cuckoo.__DoNotUse<(StashItem?), Void> where M1.OptionalMatchedType == StashItem { + let matchers: [Cuckoo.ParameterMatcher<(StashItem?)>] = [wrap(matchable: stashItem) { $0 }] + return cuckoo_manager.verify("didReceive(stashItem: StashItem?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(stashItemError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: stashItemError) { $0 }] + return cuckoo_manager.verify("didReceive(stashItemError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(ledgerInfo: M1) -> Cuckoo.__DoNotUse<(StakingLedger?), Void> where M1.OptionalMatchedType == StakingLedger { + let matchers: [Cuckoo.ParameterMatcher<(StakingLedger?)>] = [wrap(matchable: ledgerInfo) { $0 }] + return cuckoo_manager.verify("didReceive(ledgerInfo: StakingLedger?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(ledgerInfoError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: ledgerInfoError) { $0 }] + return cuckoo_manager.verify("didReceive(ledgerInfoError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(nomination: M1) -> Cuckoo.__DoNotUse<(Nomination?), Void> where M1.OptionalMatchedType == Nomination { + let matchers: [Cuckoo.ParameterMatcher<(Nomination?)>] = [wrap(matchable: nomination) { $0 }] + return cuckoo_manager.verify("didReceive(nomination: Nomination?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var totalStake: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "totalStake") + @discardableResult + func didReceive(nominationError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: nominationError) { $0 }] + return cuckoo_manager.verify("didReceive(nominationError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var ownStake: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "ownStake") + @discardableResult + func didReceive(validatorPrefs: M1) -> Cuckoo.__DoNotUse<(ValidatorPrefs?), Void> where M1.OptionalMatchedType == ValidatorPrefs { + let matchers: [Cuckoo.ParameterMatcher<(ValidatorPrefs?)>] = [wrap(matchable: validatorPrefs) { $0 }] + return cuckoo_manager.verify("didReceive(validatorPrefs: ValidatorPrefs?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var hasSlashes: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "hasSlashes") + @discardableResult + func didReceive(validatorError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: validatorError) { $0 }] + return cuckoo_manager.verify("didReceive(validatorError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var blocked: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "blocked") + @discardableResult + func didReceive(eraStakersInfo: M1) -> Cuckoo.__DoNotUse<(EraStakersInfo), Void> where M1.MatchedType == EraStakersInfo { + let matchers: [Cuckoo.ParameterMatcher<(EraStakersInfo)>] = [wrap(matchable: eraStakersInfo) { $0 }] + return cuckoo_manager.verify("didReceive(eraStakersInfo: EraStakersInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - } - - struct __VerificationProxy_ValidatorInfoProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation + @discardableResult + func didReceive(eraStakersInfoError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: eraStakersInfoError) { $0 }] + return cuckoo_manager.verify("didReceive(eraStakersInfoError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - - var address: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "address", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceive(networkStakingInfo: M1) -> Cuckoo.__DoNotUse<(NetworkStakingInfo), Void> where M1.MatchedType == NetworkStakingInfo { + let matchers: [Cuckoo.ParameterMatcher<(NetworkStakingInfo)>] = [wrap(matchable: networkStakingInfo) { $0 }] + return cuckoo_manager.verify("didReceive(networkStakingInfo: NetworkStakingInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var identity: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "identity", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceive(networkStakingInfoError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: networkStakingInfoError) { $0 }] + return cuckoo_manager.verify("didReceive(networkStakingInfoError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var stakeInfo: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "stakeInfo", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceive(payee: M1) -> Cuckoo.__DoNotUse<(RewardDestinationArg?), Void> where M1.OptionalMatchedType == RewardDestinationArg { + let matchers: [Cuckoo.ParameterMatcher<(RewardDestinationArg?)>] = [wrap(matchable: payee) { $0 }] + return cuckoo_manager.verify("didReceive(payee: RewardDestinationArg?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var myNomination: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "myNomination", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceive(payeeError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: payeeError) { $0 }] + return cuckoo_manager.verify("didReceive(payeeError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var totalStake: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "totalStake", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceive(newChainAsset: M1) -> Cuckoo.__DoNotUse<(ChainAsset), Void> where M1.MatchedType == ChainAsset { + let matchers: [Cuckoo.ParameterMatcher<(ChainAsset)>] = [wrap(matchable: newChainAsset) { $0 }] + return cuckoo_manager.verify("didReceive(newChainAsset: ChainAsset)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didReceieve(subqueryRewards: M1, period: M2) -> Cuckoo.__DoNotUse<(Result<[SubqueryRewardItemData]?, Error>, AnalyticsPeriod), Void> where M1.MatchedType == Result<[SubqueryRewardItemData]?, Error>, M2.MatchedType == AnalyticsPeriod { + let matchers: [Cuckoo.ParameterMatcher<(Result<[SubqueryRewardItemData]?, Error>, AnalyticsPeriod)>] = [wrap(matchable: subqueryRewards) { $0.0 }, wrap(matchable: period) { $0.1 }] + return cuckoo_manager.verify("didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } - var ownStake: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "ownStake", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveMinNominatorBond(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMinNominatorBond(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didReceiveCounterForNominators(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveCounterForNominators(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } - var hasSlashes: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "hasSlashes", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveMaxNominatorsCount(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMaxNominatorsCount(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didReceive(eraCountdownResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: eraCountdownResult) { $0 }] + return cuckoo_manager.verify("didReceive(eraCountdownResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } - var blocked: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "blocked", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveMaxNominatorsPerValidator(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMaxNominatorsPerValidator(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - + @discardableResult + func didReceiveAccount(_ account: M1, for accountId: M2) -> Cuckoo.__DoNotUse<(MetaChainAccountResponse?, AccountId), Void> where M1.OptionalMatchedType == MetaChainAccountResponse, M2.MatchedType == AccountId { + let matchers: [Cuckoo.ParameterMatcher<(MetaChainAccountResponse?, AccountId)>] = [wrap(matchable: account) { $0.0 }, wrap(matchable: accountId) { $0.1 }] + return cuckoo_manager.verify("didReceiveAccount(_: MetaChainAccountResponse?, for: AccountId)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } } } - class ValidatorInfoProtocolStub: ValidatorInfoProtocol { - - + class StakingRelaychainInteractorOutputProtocolStub: StakingRelaychainInteractorOutputProtocol { - var address: String { - get { - return DefaultValueRegistry.defaultValue(for: (String).self) - } - - } - + + - var identity: AccountIdentity? { - get { - return DefaultValueRegistry.defaultValue(for: (AccountIdentity?).self) - } - - } - - var stakeInfo: ValidatorStakeInfoProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (ValidatorStakeInfoProtocol?).self) - } - + func didReceive(selectedAddress: String) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - var myNomination: ValidatorMyNominationStatus? { - get { - return DefaultValueRegistry.defaultValue(for: (ValidatorMyNominationStatus?).self) - } - - } - - var totalStake: Decimal { - get { - return DefaultValueRegistry.defaultValue(for: (Decimal).self) - } - + func didReceive(price: PriceData?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - var ownStake: Decimal { - get { - return DefaultValueRegistry.defaultValue(for: (Decimal).self) - } - - } - - var hasSlashes: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + func didReceive(priceError: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var blocked: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + func didReceive(totalReward: TotalRewardItem) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - -} - - - - class MockValidatorInfoViewProtocol: ValidatorInfoViewProtocol, Cuckoo.ProtocolMock { + func didReceive(totalRewardError: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - typealias MocksType = ValidatorInfoViewProtocol - typealias Stubbing = __StubbingProxy_ValidatorInfoViewProtocol - typealias Verification = __VerificationProxy_ValidatorInfoViewProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ValidatorInfoViewProtocol? - - func enableDefaultImplementation(_ stub: ValidatorInfoViewProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func didReceive(accountInfo: AccountInfo?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - + func didReceive(balanceError: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - + func didReceive(calculator: RewardCalculatorEngineProtocol) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } - - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } - + func didReceive(calculatorError: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - - - func didRecieve(state: ValidatorInfoState) { - - return cuckoo_manager.call("didRecieve(state: ValidatorInfoState)", - parameters: (state), - escapingParameters: (state), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didRecieve(state: state)) - + func didReceive(stashItem: StashItem?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { - - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.applyLocalization()) - + func didReceive(stashItemError: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - struct __StubbingProxy_ValidatorInfoViewProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") - } - - - func didRecieve(state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoState)> where M1.MatchedType == ValidatorInfoState { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoState)>] = [wrap(matchable: state) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoViewProtocol.self, method: "didRecieve(state: ValidatorInfoState)", parameterMatchers: matchers)) - } - - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ValidatorInfoViewProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - - @discardableResult - func didRecieve(state: M1) -> Cuckoo.__DoNotUse<(ValidatorInfoState), Void> where M1.MatchedType == ValidatorInfoState { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoState)>] = [wrap(matchable: state) { $0 }] - return cuckoo_manager.verify("didRecieve(state: ValidatorInfoState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class ValidatorInfoViewProtocolStub: ValidatorInfoViewProtocol { - - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + func didReceive(ledgerInfo: StakingLedger?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - + func didReceive(ledgerInfoError: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - - - func didRecieve(state: ValidatorInfoState) { + func didReceive(nomination: Nomination?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func didReceive(nominationError: Error) { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockValidatorInfoInteractorInputProtocol: ValidatorInfoInteractorInputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ValidatorInfoInteractorInputProtocol - typealias Stubbing = __StubbingProxy_ValidatorInfoInteractorInputProtocol - typealias Verification = __VerificationProxy_ValidatorInfoInteractorInputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ValidatorInfoInteractorInputProtocol? - - func enableDefaultImplementation(_ stub: ValidatorInfoInteractorInputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func didReceive(validatorPrefs: ValidatorPrefs?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - + func didReceive(validatorError: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - + func didReceive(eraStakersInfo: EraStakersInfo) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func reload() { - - return cuckoo_manager.call("reload()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.reload()) - + func didReceive(eraStakersInfoError: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - struct __StubbingProxy_ValidatorInfoInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorInputProtocol.self, method: "reload()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ValidatorInfoInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func reload() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class ValidatorInfoInteractorInputProtocolStub: ValidatorInfoInteractorInputProtocol { - - + func didReceive(networkStakingInfo: NetworkStakingInfo) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func setup() { + func didReceive(networkStakingInfoError: Error) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func reload() { + func didReceive(payee: RewardDestinationArg?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockValidatorInfoInteractorOutputProtocol: ValidatorInfoInteractorOutputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ValidatorInfoInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_ValidatorInfoInteractorOutputProtocol - typealias Verification = __VerificationProxy_ValidatorInfoInteractorOutputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ValidatorInfoInteractorOutputProtocol? - - func enableDefaultImplementation(_ stub: ValidatorInfoInteractorOutputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func didReceive(payeeError: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - + func didReceive(newChainAsset: ChainAsset) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func didReceivePriceData(result: Result) { - - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) - + func didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoadingValidatorInfo() { - - return cuckoo_manager.call("didStartLoadingValidatorInfo()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didStartLoadingValidatorInfo()) - + func didReceiveMinNominatorBond(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveValidatorInfo(result: Result) { - - return cuckoo_manager.call("didReceiveValidatorInfo(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveValidatorInfo(result: result)) - + func didReceiveCounterForNominators(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - struct __StubbingProxy_ValidatorInfoInteractorOutputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) - } - - func didStartLoadingValidatorInfo() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorOutputProtocol.self, method: "didStartLoadingValidatorInfo()", parameterMatchers: matchers)) - } - - func didReceiveValidatorInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoInteractorOutputProtocol.self, method: "didReceiveValidatorInfo(result: Result)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ValidatorInfoInteractorOutputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didStartLoadingValidatorInfo() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoadingValidatorInfo()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveValidatorInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveValidatorInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class ValidatorInfoInteractorOutputProtocolStub: ValidatorInfoInteractorOutputProtocol { - - + func didReceiveMaxNominatorsCount(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func didReceivePriceData(result: Result) { + func didReceive(eraCountdownResult: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoadingValidatorInfo() { + func didReceiveMaxNominatorsPerValidator(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveValidatorInfo(result: Result) { + func didReceiveAccount(_ account: MetaChainAccountResponse?, for accountId: AccountId) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -34899,19 +34188,19 @@ import SoraFoundation - class MockValidatorInfoPresenterProtocol: ValidatorInfoPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingRelaychainWireframeProtocol: StakingRelaychainWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorInfoPresenterProtocol + typealias MocksType = StakingRelaychainWireframeProtocol - typealias Stubbing = __StubbingProxy_ValidatorInfoPresenterProtocol - typealias Verification = __VerificationProxy_ValidatorInfoPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingRelaychainWireframeProtocol + typealias Verification = __VerificationProxy_StakingRelaychainWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorInfoPresenterProtocol? + private var __defaultImplStub: StakingRelaychainWireframeProtocol? - func enableDefaultImplementation(_ stub: ValidatorInfoPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingRelaychainWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -34924,468 +34213,246 @@ import SoraFoundation - func setup() { + func showSetupAmount(from view: StakingMainViewProtocol?) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("showSetupAmount(from: StakingMainViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.showSetupAmount(from: view)) } - func reload() { + func proceedToSelectValidatorsStart(from view: StakingMainViewProtocol?, existingBonding: ExistingBonding) { - return cuckoo_manager.call("reload()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("proceedToSelectValidatorsStart(from: StakingMainViewProtocol?, existingBonding: ExistingBonding)", + parameters: (view, existingBonding), + escapingParameters: (view, existingBonding), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload()) + defaultCall: __defaultImplStub!.proceedToSelectValidatorsStart(from: view, existingBonding: existingBonding)) } - func presentAccountOptions() { + func showRewardDetails(from view: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal) { - return cuckoo_manager.call("presentAccountOptions()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("showRewardDetails(from: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal)", + parameters: (view, maxReward, avgReward), + escapingParameters: (view, maxReward, avgReward), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentAccountOptions()) + defaultCall: __defaultImplStub!.showRewardDetails(from: view, maxReward: maxReward, avgReward: avgReward)) } - func presentTotalStake() { + func showRewardPayoutsForNominator(from view: ControllerBackedProtocol?, stashAddress: AccountAddress) { - return cuckoo_manager.call("presentTotalStake()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("showRewardPayoutsForNominator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", + parameters: (view, stashAddress), + escapingParameters: (view, stashAddress), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentTotalStake()) + defaultCall: __defaultImplStub!.showRewardPayoutsForNominator(from: view, stashAddress: stashAddress)) } - func presentIdentityItem(_ value: ValidatorInfoViewModel.IdentityItemValue) { + func showRewardPayoutsForValidator(from view: ControllerBackedProtocol?, stashAddress: AccountAddress) { - return cuckoo_manager.call("presentIdentityItem(_: ValidatorInfoViewModel.IdentityItemValue)", - parameters: (value), - escapingParameters: (value), + return cuckoo_manager.call("showRewardPayoutsForValidator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", + parameters: (view, stashAddress), + escapingParameters: (view, stashAddress), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentIdentityItem(value)) + defaultCall: __defaultImplStub!.showRewardPayoutsForValidator(from: view, stashAddress: stashAddress)) } - - struct __StubbingProxy_ValidatorInfoPresenterProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "reload()", parameterMatchers: matchers)) - } - - func presentAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "presentAccountOptions()", parameterMatchers: matchers)) - } - - func presentTotalStake() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "presentTotalStake()", parameterMatchers: matchers)) - } - - func presentIdentityItem(_ value: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoViewModel.IdentityItemValue)> where M1.MatchedType == ValidatorInfoViewModel.IdentityItemValue { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoViewModel.IdentityItemValue)>] = [wrap(matchable: value) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorInfoPresenterProtocol.self, method: "presentIdentityItem(_: ValidatorInfoViewModel.IdentityItemValue)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ValidatorInfoPresenterProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func reload() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func presentAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func presentTotalStake() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentTotalStake()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func presentIdentityItem(_ value: M1) -> Cuckoo.__DoNotUse<(ValidatorInfoViewModel.IdentityItemValue), Void> where M1.MatchedType == ValidatorInfoViewModel.IdentityItemValue { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoViewModel.IdentityItemValue)>] = [wrap(matchable: value) { $0 }] - return cuckoo_manager.verify("presentIdentityItem(_: ValidatorInfoViewModel.IdentityItemValue)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class ValidatorInfoPresenterProtocolStub: ValidatorInfoPresenterProtocol { - - - - - - - - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func reload() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func presentAccountOptions() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func presentTotalStake() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func presentIdentityItem(_ value: ValidatorInfoViewModel.IdentityItemValue) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - - - class MockValidatorInfoWireframeProtocol: ValidatorInfoWireframeProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ValidatorInfoWireframeProtocol - typealias Stubbing = __StubbingProxy_ValidatorInfoWireframeProtocol - typealias Verification = __VerificationProxy_ValidatorInfoWireframeProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ValidatorInfoWireframeProtocol? - - func enableDefaultImplementation(_ stub: ValidatorInfoWireframeProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func showNominatorValidators(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showNominatorValidators(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showNominatorValidators(from: view)) + } - - - - - - - - struct __StubbingProxy_ValidatorInfoWireframeProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - } - - struct __VerificationProxy_ValidatorInfoWireframeProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - } -} - - class ValidatorInfoWireframeProtocolStub: ValidatorInfoWireframeProtocol { - - - - - -} - - -import Cuckoo -@testable import novawallet - -import SoraFoundation - - - class MockValidatorListFilterWireframeProtocol: ValidatorListFilterWireframeProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ValidatorListFilterWireframeProtocol - typealias Stubbing = __StubbingProxy_ValidatorListFilterWireframeProtocol - typealias Verification = __VerificationProxy_ValidatorListFilterWireframeProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ValidatorListFilterWireframeProtocol? - - func enableDefaultImplementation(_ stub: ValidatorListFilterWireframeProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func showRewardDestination(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showRewardDestination(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showRewardDestination(from: view)) + } - - - - - - - func close(_ view: ControllerBackedProtocol?) { + func showControllerAccount(from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("close(_: ControllerBackedProtocol?)", + return cuckoo_manager.call("showControllerAccount(from: ControllerBackedProtocol?)", parameters: (view), escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(view)) + defaultCall: __defaultImplStub!.showControllerAccount(from: view)) } - - struct __StubbingProxy_ValidatorListFilterWireframeProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func close(_ view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterWireframeProtocol.self, method: "close(_: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ValidatorListFilterWireframeProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func close(_ view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(_: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class ValidatorListFilterWireframeProtocolStub: ValidatorListFilterWireframeProtocol { - - - - - - func close(_ view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func showBondMore(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showBondMore(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showBondMore(from: view)) + } -} - - - - class MockValidatorListFilterViewProtocol: ValidatorListFilterViewProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ValidatorListFilterViewProtocol - typealias Stubbing = __StubbingProxy_ValidatorListFilterViewProtocol - typealias Verification = __VerificationProxy_ValidatorListFilterViewProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ValidatorListFilterViewProtocol? - - func enableDefaultImplementation(_ stub: ValidatorListFilterViewProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func showUnbond(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showUnbond(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showUnbond(from: view)) + } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } + func showRedeem(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showRedeem(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showRedeem(from: view)) } - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } + func showRebond(from view: ControllerBackedProtocol?, option: StakingRebondOption) { + + return cuckoo_manager.call("showRebond(from: ControllerBackedProtocol?, option: StakingRebondOption)", + parameters: (view, option), + escapingParameters: (view, option), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showRebond(from: view, option: option)) } - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } + func showAnalytics(from view: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode) { - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } + return cuckoo_manager.call("showAnalytics(from: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode)", + parameters: (view, mode), + escapingParameters: (view, mode), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showAnalytics(from: view, mode: mode)) } - - + + func showYourValidatorInfo(_ stashAddress: AccountAddress, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showYourValidatorInfo(_: AccountAddress, from: ControllerBackedProtocol?)", + parameters: (stashAddress, view), + escapingParameters: (stashAddress, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showYourValidatorInfo(stashAddress, from: view)) + + } - func didUpdateViewModel(_ viewModel: ValidatorListFilterViewModel) { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("didUpdateViewModel(_: ValidatorListFilterViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didUpdateViewModel(viewModel)) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - public func applyLocalization() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_ValidatorListFilterViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRelaychainWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -35393,34 +34460,89 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") + func showSetupAmount(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainViewProtocol?)> where M1.OptionalMatchedType == StakingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showSetupAmount(from: StakingMainViewProtocol?)", parameterMatchers: matchers)) + } + + func proceedToSelectValidatorsStart(from view: M1, existingBonding: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainViewProtocol?, ExistingBonding)> where M1.OptionalMatchedType == StakingMainViewProtocol, M2.MatchedType == ExistingBonding { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?, ExistingBonding)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: existingBonding) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "proceedToSelectValidatorsStart(from: StakingMainViewProtocol?, existingBonding: ExistingBonding)", parameterMatchers: matchers)) } + func showRewardDetails(from view: M1, maxReward: M2, avgReward: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, Decimal, Decimal)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == Decimal, M3.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, Decimal, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: maxReward) { $0.1 }, wrap(matchable: avgReward) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRewardDetails(from: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal)", parameterMatchers: matchers)) + } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") + func showRewardPayoutsForNominator(from view: M1, stashAddress: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, AccountAddress)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AccountAddress)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: stashAddress) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRewardPayoutsForNominator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", parameterMatchers: matchers)) } + func showRewardPayoutsForValidator(from view: M1, stashAddress: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, AccountAddress)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AccountAddress)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: stashAddress) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRewardPayoutsForValidator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", parameterMatchers: matchers)) + } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") + func showNominatorValidators(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showNominatorValidators(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } + func showRewardDestination(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRewardDestination(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } - func didUpdateViewModel(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorListFilterViewModel)> where M1.MatchedType == ValidatorListFilterViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterViewProtocol.self, method: "didUpdateViewModel(_: ValidatorListFilterViewModel)", parameterMatchers: matchers)) + func showControllerAccount(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showControllerAccount(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func showBondMore(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showBondMore(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showUnbond(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showUnbond(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showRedeem(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRedeem(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showRebond(from view: M1, option: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, StakingRebondOption)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == StakingRebondOption { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, StakingRebondOption)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: option) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRebond(from: ControllerBackedProtocol?, option: StakingRebondOption)", parameterMatchers: matchers)) + } + + func showAnalytics(from view: M1, mode: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, AnalyticsContainerViewMode)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AnalyticsContainerViewMode { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AnalyticsContainerViewMode)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: mode) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showAnalytics(from: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode)", parameterMatchers: matchers)) + } + + func showYourValidatorInfo(_ stashAddress: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress, ControllerBackedProtocol?)> where M1.MatchedType == AccountAddress, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress, ControllerBackedProtocol?)>] = [wrap(matchable: stashAddress) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showYourValidatorInfo(_: AccountAddress, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ValidatorListFilterViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRelaychainWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -35432,102 +34554,234 @@ import SoraFoundation } + - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func showSetupAmount(from view: M1) -> Cuckoo.__DoNotUse<(StakingMainViewProtocol?), Void> where M1.OptionalMatchedType == StakingMainViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showSetupAmount(from: StakingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func proceedToSelectValidatorsStart(from view: M1, existingBonding: M2) -> Cuckoo.__DoNotUse<(StakingMainViewProtocol?, ExistingBonding), Void> where M1.OptionalMatchedType == StakingMainViewProtocol, M2.MatchedType == ExistingBonding { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?, ExistingBonding)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: existingBonding) { $0.1 }] + return cuckoo_manager.verify("proceedToSelectValidatorsStart(from: StakingMainViewProtocol?, existingBonding: ExistingBonding)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func showRewardDetails(from view: M1, maxReward: M2, avgReward: M3) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, Decimal, Decimal), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == Decimal, M3.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, Decimal, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: maxReward) { $0.1 }, wrap(matchable: avgReward) { $0.2 }] + return cuckoo_manager.verify("showRewardDetails(from: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func showRewardPayoutsForNominator(from view: M1, stashAddress: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, AccountAddress), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AccountAddress)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: stashAddress) { $0.1 }] + return cuckoo_manager.verify("showRewardPayoutsForNominator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func showRewardPayoutsForValidator(from view: M1, stashAddress: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, AccountAddress), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AccountAddress)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: stashAddress) { $0.1 }] + return cuckoo_manager.verify("showRewardPayoutsForValidator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - + @discardableResult + func showNominatorValidators(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showNominatorValidators(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } @discardableResult - func didUpdateViewModel(_ viewModel: M1) -> Cuckoo.__DoNotUse<(ValidatorListFilterViewModel), Void> where M1.MatchedType == ValidatorListFilterViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didUpdateViewModel(_: ValidatorListFilterViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showRewardDestination(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showRewardDestination(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showControllerAccount(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showControllerAccount(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showBondMore(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showBondMore(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showUnbond(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showUnbond(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showRedeem(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showRedeem(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showRebond(from view: M1, option: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, StakingRebondOption), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == StakingRebondOption { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, StakingRebondOption)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: option) { $0.1 }] + return cuckoo_manager.verify("showRebond(from: ControllerBackedProtocol?, option: StakingRebondOption)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showAnalytics(from view: M1, mode: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, AnalyticsContainerViewMode), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AnalyticsContainerViewMode { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AnalyticsContainerViewMode)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: mode) { $0.1 }] + return cuckoo_manager.verify("showAnalytics(from: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showYourValidatorInfo(_ stashAddress: M1, from view: M2) -> Cuckoo.__DoNotUse<(AccountAddress, ControllerBackedProtocol?), Void> where M1.MatchedType == AccountAddress, M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress, ControllerBackedProtocol?)>] = [wrap(matchable: stashAddress) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("showYourValidatorInfo(_: AccountAddress, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ValidatorListFilterViewProtocolStub: ValidatorListFilterViewProtocol { - + class StakingRelaychainWireframeProtocolStub: StakingRelaychainWireframeProtocol { + - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + + + + func showSetupAmount(from view: StakingMainViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - + + func proceedToSelectValidatorsStart(from view: StakingMainViewProtocol?, existingBonding: ExistingBonding) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - + + func showRewardDetails(from view: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - + func showRewardPayoutsForNominator(from view: ControllerBackedProtocol?, stashAddress: AccountAddress) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func didUpdateViewModel(_ viewModel: ValidatorListFilterViewModel) { + + func showRewardPayoutsForValidator(from view: ControllerBackedProtocol?, stashAddress: AccountAddress) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func showNominatorValidators(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showRewardDestination(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showControllerAccount(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showBondMore(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showUnbond(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showRedeem(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showRebond(from view: ControllerBackedProtocol?, option: StakingRebondOption) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showAnalytics(from view: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showYourValidatorInfo(_ stashAddress: AccountAddress, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet - class MockValidatorListFilterPresenterProtocol: ValidatorListFilterPresenterProtocol, Cuckoo.ProtocolMock { +import BigInt +import CommonWallet +import Foundation +import SoraFoundation + + + class MockStakingMainViewProtocol: StakingMainViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorListFilterPresenterProtocol + typealias MocksType = StakingMainViewProtocol - typealias Stubbing = __StubbingProxy_ValidatorListFilterPresenterProtocol - typealias Verification = __VerificationProxy_ValidatorListFilterPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingMainViewProtocol + typealias Verification = __VerificationProxy_StakingMainViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorListFilterPresenterProtocol? + private var __defaultImplStub: StakingMainViewProtocol? - func enableDefaultImplementation(_ stub: ValidatorListFilterPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingMainViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -35536,24 +34790,28 @@ import SoraFoundation - var view: ValidatorListFilterViewProtocol? { + var isSetup: Bool { get { - return cuckoo_manager.getter("view", + return cuckoo_manager.getter("isSetup", superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.view) + defaultCall: __defaultImplStub!.isSetup) } - set { - cuckoo_manager.setter("view", - value: newValue, + } + + + + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.view = newValue) + defaultCall: __defaultImplStub!.controller) } } @@ -35588,76 +34846,76 @@ import SoraFoundation - func setup() { + func didReceive(viewModel: StakingMainViewModel) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(viewModel: StakingMainViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) } - func toggleFilter(for viewModel: ValidatorListFilterCellViewModel) { + func didRecieveNetworkStakingInfo(viewModel: LocalizableResource?) { - return cuckoo_manager.call("toggleFilter(for: ValidatorListFilterCellViewModel)", + return cuckoo_manager.call("didRecieveNetworkStakingInfo(viewModel: LocalizableResource?)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.toggleFilter(for: viewModel)) + defaultCall: __defaultImplStub!.didRecieveNetworkStakingInfo(viewModel: viewModel)) } - func selectSorting(for viewModel: ValidatorListFilterCellViewModel) { + func didReceiveStakingState(viewModel: StakingViewState) { - return cuckoo_manager.call("selectSorting(for: ValidatorListFilterCellViewModel)", + return cuckoo_manager.call("didReceiveStakingState(viewModel: StakingViewState)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectSorting(for: viewModel)) + defaultCall: __defaultImplStub!.didReceiveStakingState(viewModel: viewModel)) } - func applyFilter() { + func expandNetworkInfoView(_ isExpanded: Bool) { - return cuckoo_manager.call("applyFilter()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("expandNetworkInfoView(_: Bool)", + parameters: (isExpanded), + escapingParameters: (isExpanded), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyFilter()) + defaultCall: __defaultImplStub!.expandNetworkInfoView(isExpanded)) } - func resetFilter() { + func didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol) { - return cuckoo_manager.call("resetFilter()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.resetFilter()) + defaultCall: __defaultImplStub!.didReceiveStatics(viewModel: viewModel)) } @@ -35677,7 +34935,7 @@ import SoraFoundation } - struct __StubbingProxy_ValidatorListFilterPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingMainViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -35685,49 +34943,54 @@ import SoraFoundation } - var view: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "view") + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func toggleFilter(for viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorListFilterCellViewModel)> where M1.MatchedType == ValidatorListFilterCellViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterCellViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "toggleFilter(for: ValidatorListFilterCellViewModel)", parameterMatchers: matchers)) + + func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainViewModel)> where M1.MatchedType == StakingMainViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "didReceive(viewModel: StakingMainViewModel)", parameterMatchers: matchers)) } - func selectSorting(for viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorListFilterCellViewModel)> where M1.MatchedType == ValidatorListFilterCellViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterCellViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "selectSorting(for: ValidatorListFilterCellViewModel)", parameterMatchers: matchers)) + func didRecieveNetworkStakingInfo(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "didRecieveNetworkStakingInfo(viewModel: LocalizableResource?)", parameterMatchers: matchers)) } - func applyFilter() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "applyFilter()", parameterMatchers: matchers)) + func didReceiveStakingState(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingViewState)> where M1.MatchedType == StakingViewState { + let matchers: [Cuckoo.ParameterMatcher<(StakingViewState)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "didReceiveStakingState(viewModel: StakingViewState)", parameterMatchers: matchers)) } - func resetFilter() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "resetFilter()", parameterMatchers: matchers)) + func expandNetworkInfoView(_ isExpanded: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "expandNetworkInfoView(_: Bool)", parameterMatchers: matchers)) + } + + func didReceiveStatics(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainStaticViewModelProtocol)> where M1.MatchedType == StakingMainStaticViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainStaticViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterPresenterProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_ValidatorListFilterPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingMainViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -35740,8 +35003,13 @@ import SoraFoundation - var view: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "view", callMatcher: callMatcher, sourceLocation: sourceLocation) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } @@ -35752,33 +35020,33 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingMainViewModel), Void> where M1.MatchedType == StakingMainViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceive(viewModel: StakingMainViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func toggleFilter(for viewModel: M1) -> Cuckoo.__DoNotUse<(ValidatorListFilterCellViewModel), Void> where M1.MatchedType == ValidatorListFilterCellViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterCellViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("toggleFilter(for: ValidatorListFilterCellViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didRecieveNetworkStakingInfo(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didRecieveNetworkStakingInfo(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectSorting(for viewModel: M1) -> Cuckoo.__DoNotUse<(ValidatorListFilterCellViewModel), Void> where M1.MatchedType == ValidatorListFilterCellViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorListFilterCellViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("selectSorting(for: ValidatorListFilterCellViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStakingState(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingViewState), Void> where M1.MatchedType == StakingViewState { + let matchers: [Cuckoo.ParameterMatcher<(StakingViewState)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveStakingState(viewModel: StakingViewState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyFilter() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyFilter()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func expandNetworkInfoView(_ isExpanded: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] + return cuckoo_manager.verify("expandNetworkInfoView(_: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func resetFilter() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("resetFilter()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStatics(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingMainStaticViewModelProtocol), Void> where M1.MatchedType == StakingMainStaticViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainStaticViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -35790,16 +35058,23 @@ import SoraFoundation } } - class ValidatorListFilterPresenterProtocolStub: ValidatorListFilterPresenterProtocol { + class StakingMainViewProtocolStub: StakingMainViewProtocol { - var view: ValidatorListFilterViewProtocol? { + var isSetup: Bool { get { - return DefaultValueRegistry.defaultValue(for: (ValidatorListFilterViewProtocol?).self) + return DefaultValueRegistry.defaultValue(for: (Bool).self) } - set { } + } + + + + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } } @@ -35820,31 +35095,31 @@ import SoraFoundation - func setup() { + func didReceive(viewModel: StakingMainViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func toggleFilter(for viewModel: ValidatorListFilterCellViewModel) { + func didRecieveNetworkStakingInfo(viewModel: LocalizableResource?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectSorting(for viewModel: ValidatorListFilterCellViewModel) { + func didReceiveStakingState(viewModel: StakingViewState) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func applyFilter() { + func expandNetworkInfoView(_ isExpanded: Bool) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func resetFilter() { + func didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -35858,19 +35133,19 @@ import SoraFoundation - class MockValidatorListFilterDelegate: ValidatorListFilterDelegate, Cuckoo.ProtocolMock { + class MockStakingMainPresenterProtocol: StakingMainPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorListFilterDelegate + typealias MocksType = StakingMainPresenterProtocol - typealias Stubbing = __StubbingProxy_ValidatorListFilterDelegate - typealias Verification = __VerificationProxy_ValidatorListFilterDelegate + typealias Stubbing = __StubbingProxy_StakingMainPresenterProtocol + typealias Verification = __VerificationProxy_StakingMainPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorListFilterDelegate? + private var __defaultImplStub: StakingMainPresenterProtocol? - func enableDefaultImplementation(_ stub: ValidatorListFilterDelegate) { + func enableDefaultImplementation(_ stub: StakingMainPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -35883,164 +35158,201 @@ import SoraFoundation - func didUpdate(_ filter: CustomValidatorListFilter) { + func setup() { - return cuckoo_manager.call("didUpdate(_: CustomValidatorListFilter)", - parameters: (filter), - escapingParameters: (filter), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didUpdate(filter)) + defaultCall: __defaultImplStub!.setup()) } - - struct __StubbingProxy_ValidatorListFilterDelegate: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func didUpdate(_ filter: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CustomValidatorListFilter)> where M1.MatchedType == CustomValidatorListFilter { - let matchers: [Cuckoo.ParameterMatcher<(CustomValidatorListFilter)>] = [wrap(matchable: filter) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorListFilterDelegate.self, method: "didUpdate(_: CustomValidatorListFilter)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ValidatorListFilterDelegate: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func didUpdate(_ filter: M1) -> Cuckoo.__DoNotUse<(CustomValidatorListFilter), Void> where M1.MatchedType == CustomValidatorListFilter { - let matchers: [Cuckoo.ParameterMatcher<(CustomValidatorListFilter)>] = [wrap(matchable: filter) { $0 }] - return cuckoo_manager.verify("didUpdate(_: CustomValidatorListFilter)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class ValidatorListFilterDelegateStub: ValidatorListFilterDelegate { - - + func performAssetSelection() { + + return cuckoo_manager.call("performAssetSelection()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performAssetSelection()) + + } - func didUpdate(_ filter: CustomValidatorListFilter) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func performMainAction() { + + return cuckoo_manager.call("performMainAction()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performMainAction()) + } -} - - -import Cuckoo -@testable import novawallet - -import SoraFoundation - - - class MockValidatorSearchWireframeProtocol: ValidatorSearchWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorSearchWireframeProtocol - typealias Stubbing = __StubbingProxy_ValidatorSearchWireframeProtocol - typealias Verification = __VerificationProxy_ValidatorSearchWireframeProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - + func performAccountAction() { + + return cuckoo_manager.call("performAccountAction()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performAccountAction()) + + } - private var __defaultImplStub: ValidatorSearchWireframeProtocol? - - func enableDefaultImplementation(_ stub: ValidatorSearchWireframeProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + + + func performRewardInfoAction() { + + return cuckoo_manager.call("performRewardInfoAction()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performRewardInfoAction()) + } - - - + func performChangeValidatorsAction() { + + return cuckoo_manager.call("performChangeValidatorsAction()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performChangeValidatorsAction()) + + } - func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { + func performSetupValidatorsForBondedAction() { - return cuckoo_manager.call("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", - parameters: (validatorInfo, view), - escapingParameters: (validatorInfo, view), + return cuckoo_manager.call("performSetupValidatorsForBondedAction()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) + defaultCall: __defaultImplStub!.performSetupValidatorsForBondedAction()) } - func close(_ view: ControllerBackedProtocol?) { + func performStakeMoreAction() { - return cuckoo_manager.call("close(_: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("performStakeMoreAction()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(view)) + defaultCall: __defaultImplStub!.performStakeMoreAction()) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func performRedeemAction() { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("performRedeemAction()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.performRedeemAction()) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func performRebondAction() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("performRebondAction()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.performRebondAction()) + + } + + + + func performAnalyticsAction() { + + return cuckoo_manager.call("performAnalyticsAction()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performAnalyticsAction()) + + } + + + + func networkInfoViewDidChangeExpansion(isExpanded: Bool) { + + return cuckoo_manager.call("networkInfoViewDidChangeExpansion(isExpanded: Bool)", + parameters: (isExpanded), + escapingParameters: (isExpanded), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.networkInfoViewDidChangeExpansion(isExpanded: isExpanded)) + + } + + + + func performManageAction(_ action: StakingManageOption) { + + return cuckoo_manager.call("performManageAction(_: StakingManageOption)", + parameters: (action), + escapingParameters: (action), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performManageAction(action)) } - struct __StubbingProxy_ValidatorSearchWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingMainPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -36048,29 +35360,74 @@ import SoraFoundation } - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoProtocol, ControllerBackedProtocol?)> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchWireframeProtocol.self, method: "present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func close(_ view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchWireframeProtocol.self, method: "close(_: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func performAssetSelection() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performAssetSelection()", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func performMainAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performMainAction()", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func performAccountAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performAccountAction()", parameterMatchers: matchers)) + } + + func performRewardInfoAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performRewardInfoAction()", parameterMatchers: matchers)) + } + + func performChangeValidatorsAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performChangeValidatorsAction()", parameterMatchers: matchers)) + } + + func performSetupValidatorsForBondedAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performSetupValidatorsForBondedAction()", parameterMatchers: matchers)) + } + + func performStakeMoreAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performStakeMoreAction()", parameterMatchers: matchers)) + } + + func performRedeemAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performRedeemAction()", parameterMatchers: matchers)) + } + + func performRebondAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performRebondAction()", parameterMatchers: matchers)) + } + + func performAnalyticsAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performAnalyticsAction()", parameterMatchers: matchers)) + } + + func networkInfoViewDidChangeExpansion(isExpanded: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "networkInfoViewDidChangeExpansion(isExpanded: Bool)", parameterMatchers: matchers)) + } + + func performManageAction(_ action: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingManageOption)> where M1.MatchedType == StakingManageOption { + let matchers: [Cuckoo.ParameterMatcher<(StakingManageOption)>] = [wrap(matchable: action) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performManageAction(_: StakingManageOption)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ValidatorSearchWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingMainPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -36085,33 +35442,87 @@ import SoraFoundation @discardableResult - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(ValidatorInfoProtocol, ControllerBackedProtocol?), Void> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, ControllerBackedProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("present(_: ValidatorInfoProtocol, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func close(_ view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(_: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func performAssetSelection() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performAssetSelection()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func performMainAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performMainAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func performAccountAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performAccountAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performRewardInfoAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performRewardInfoAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performChangeValidatorsAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performChangeValidatorsAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performSetupValidatorsForBondedAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performSetupValidatorsForBondedAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performStakeMoreAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performStakeMoreAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performRedeemAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performRedeemAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performRebondAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performRebondAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performAnalyticsAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performAnalyticsAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func networkInfoViewDidChangeExpansion(isExpanded: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] + return cuckoo_manager.verify("networkInfoViewDidChangeExpansion(isExpanded: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performManageAction(_ action: M1) -> Cuckoo.__DoNotUse<(StakingManageOption), Void> where M1.MatchedType == StakingManageOption { + let matchers: [Cuckoo.ParameterMatcher<(StakingManageOption)>] = [wrap(matchable: action) { $0 }] + return cuckoo_manager.verify("performManageAction(_: StakingManageOption)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ValidatorSearchWireframeProtocolStub: ValidatorSearchWireframeProtocol { + class StakingMainPresenterProtocolStub: StakingMainPresenterProtocol { @@ -36119,25 +35530,79 @@ import SoraFoundation - func present(_ validatorInfo: ValidatorInfoProtocol, from view: ControllerBackedProtocol?) { + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func performAssetSelection() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func performMainAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func performAccountAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func performRewardInfoAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func performChangeValidatorsAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func performSetupValidatorsForBondedAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func performStakeMoreAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func performRedeemAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func performRebondAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func close(_ view: ControllerBackedProtocol?) { + func performAnalyticsAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func networkInfoViewDidChangeExpansion(isExpanded: Bool) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func performManageAction(_ action: StakingManageOption) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -36145,19 +35610,19 @@ import SoraFoundation - class MockValidatorSearchDelegate: ValidatorSearchDelegate, Cuckoo.ProtocolMock { + class MockStakingMainInteractorInputProtocol: StakingMainInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorSearchDelegate + typealias MocksType = StakingMainInteractorInputProtocol - typealias Stubbing = __StubbingProxy_ValidatorSearchDelegate - typealias Verification = __VerificationProxy_ValidatorSearchDelegate + typealias Stubbing = __StubbingProxy_StakingMainInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingMainInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorSearchDelegate? + private var __defaultImplStub: StakingMainInteractorInputProtocol? - func enableDefaultImplementation(_ stub: ValidatorSearchDelegate) { + func enableDefaultImplementation(_ stub: StakingMainInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -36170,21 +35635,51 @@ import SoraFoundation - func validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo]) { + func setup() { - return cuckoo_manager.call("validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo])", - parameters: (selectedValidatorList), - escapingParameters: (selectedValidatorList), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.validatorSearchDidUpdate(selectedValidatorList: selectedValidatorList)) + defaultCall: __defaultImplStub!.setup()) + + } + + + + func saveNetworkInfoViewExpansion(isExpanded: Bool) { + + return cuckoo_manager.call("saveNetworkInfoViewExpansion(isExpanded: Bool)", + parameters: (isExpanded), + escapingParameters: (isExpanded), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.saveNetworkInfoViewExpansion(isExpanded: isExpanded)) + + } + + + + func save(chainAsset: ChainAsset) { + + return cuckoo_manager.call("save(chainAsset: ChainAsset)", + parameters: (chainAsset), + escapingParameters: (chainAsset), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.save(chainAsset: chainAsset)) } - struct __StubbingProxy_ValidatorSearchDelegate: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingMainInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -36192,14 +35687,24 @@ import SoraFoundation } - func validatorSearchDidUpdate(selectedValidatorList: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([SelectedValidatorInfo])> where M1.MatchedType == [SelectedValidatorInfo] { - let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo])>] = [wrap(matchable: selectedValidatorList) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchDelegate.self, method: "validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo])", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func saveNetworkInfoViewExpansion(isExpanded: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorInputProtocol.self, method: "saveNetworkInfoViewExpansion(isExpanded: Bool)", parameterMatchers: matchers)) + } + + func save(chainAsset: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainAsset)> where M1.MatchedType == ChainAsset { + let matchers: [Cuckoo.ParameterMatcher<(ChainAsset)>] = [wrap(matchable: chainAsset) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorInputProtocol.self, method: "save(chainAsset: ChainAsset)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ValidatorSearchDelegate: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingMainInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -36214,15 +35719,27 @@ import SoraFoundation @discardableResult - func validatorSearchDidUpdate(selectedValidatorList: M1) -> Cuckoo.__DoNotUse<([SelectedValidatorInfo]), Void> where M1.MatchedType == [SelectedValidatorInfo] { - let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo])>] = [wrap(matchable: selectedValidatorList) { $0 }] - return cuckoo_manager.verify("validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func saveNetworkInfoViewExpansion(isExpanded: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] + return cuckoo_manager.verify("saveNetworkInfoViewExpansion(isExpanded: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func save(chainAsset: M1) -> Cuckoo.__DoNotUse<(ChainAsset), Void> where M1.MatchedType == ChainAsset { + let matchers: [Cuckoo.ParameterMatcher<(ChainAsset)>] = [wrap(matchable: chainAsset) { $0 }] + return cuckoo_manager.verify("save(chainAsset: ChainAsset)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ValidatorSearchDelegateStub: ValidatorSearchDelegate { + class StakingMainInteractorInputProtocolStub: StakingMainInteractorInputProtocol { @@ -36230,7 +35747,19 @@ import SoraFoundation - func validatorSearchDidUpdate(selectedValidatorList: [SelectedValidatorInfo]) { + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func saveNetworkInfoViewExpansion(isExpanded: Bool) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func save(chainAsset: ChainAsset) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -36238,158 +35767,106 @@ import SoraFoundation - class MockValidatorSearchViewProtocol: ValidatorSearchViewProtocol, Cuckoo.ProtocolMock { + class MockStakingMainInteractorOutputProtocol: StakingMainInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorSearchViewProtocol + typealias MocksType = StakingMainInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_ValidatorSearchViewProtocol - typealias Verification = __VerificationProxy_ValidatorSearchViewProtocol + typealias Stubbing = __StubbingProxy_StakingMainInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingMainInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorSearchViewProtocol? + private var __defaultImplStub: StakingMainInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: ValidatorSearchViewProtocol) { + func enableDefaultImplementation(_ stub: StakingMainInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } - - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } - - } - - func didReload(_ viewModel: ValidatorSearchViewModel) { + func didReceiveAccountInfo(_ accountInfo: AccountInfo?) { - return cuckoo_manager.call("didReload(_: ValidatorSearchViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didReceiveAccountInfo(_: AccountInfo?)", + parameters: (accountInfo), + escapingParameters: (accountInfo), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReload(viewModel)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(accountInfo)) } - func didStartSearch() { + func didReceiveSelectedAccount(_ metaAccount: MetaAccountModel) { - return cuckoo_manager.call("didStartSearch()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveSelectedAccount(_: MetaAccountModel)", + parameters: (metaAccount), + escapingParameters: (metaAccount), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStartSearch()) + defaultCall: __defaultImplStub!.didReceiveSelectedAccount(metaAccount)) } - func didStopSearch() { + func didReceiveStakingSettings(_ stakingSettings: StakingAssetSettings) { - return cuckoo_manager.call("didStopSearch()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveStakingSettings(_: StakingAssetSettings)", + parameters: (stakingSettings), + escapingParameters: (stakingSettings), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopSearch()) + defaultCall: __defaultImplStub!.didReceiveStakingSettings(stakingSettings)) } - func didReset() { + func didReceiveExpansion(_ isExpanded: Bool) { - return cuckoo_manager.call("didReset()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveExpansion(_: Bool)", + parameters: (isExpanded), + escapingParameters: (isExpanded), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReset()) + defaultCall: __defaultImplStub!.didReceiveExpansion(isExpanded)) } - public func applyLocalization() { + func didReceiveError(_ error: Error) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveError(_: Error)", + parameters: (error), + escapingParameters: (error), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.didReceiveError(error)) } - struct __StubbingProxy_ValidatorSearchViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingMainInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -36397,49 +35874,34 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") - } - - - func didReload(_ viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorSearchViewModel)> where M1.MatchedType == ValidatorSearchViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorSearchViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "didReload(_: ValidatorSearchViewModel)", parameterMatchers: matchers)) + func didReceiveAccountInfo(_ accountInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountInfo?)> where M1.OptionalMatchedType == AccountInfo { + let matchers: [Cuckoo.ParameterMatcher<(AccountInfo?)>] = [wrap(matchable: accountInfo) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveAccountInfo(_: AccountInfo?)", parameterMatchers: matchers)) } - func didStartSearch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "didStartSearch()", parameterMatchers: matchers)) + func didReceiveSelectedAccount(_ metaAccount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(MetaAccountModel)> where M1.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: metaAccount) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveSelectedAccount(_: MetaAccountModel)", parameterMatchers: matchers)) } - func didStopSearch() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "didStopSearch()", parameterMatchers: matchers)) + func didReceiveStakingSettings(_ stakingSettings: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingAssetSettings)> where M1.MatchedType == StakingAssetSettings { + let matchers: [Cuckoo.ParameterMatcher<(StakingAssetSettings)>] = [wrap(matchable: stakingSettings) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveStakingSettings(_: StakingAssetSettings)", parameterMatchers: matchers)) } - func didReset() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "didReset()", parameterMatchers: matchers)) + func didReceiveExpansion(_ isExpanded: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveExpansion(_: Bool)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func didReceiveError(_ error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveError(_: Error)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ValidatorSearchViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingMainInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -36451,86 +35913,42 @@ import SoraFoundation } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReload(_ viewModel: M1) -> Cuckoo.__DoNotUse<(ValidatorSearchViewModel), Void> where M1.MatchedType == ValidatorSearchViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorSearchViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReload(_: ValidatorSearchViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(_ accountInfo: M1) -> Cuckoo.__DoNotUse<(AccountInfo?), Void> where M1.OptionalMatchedType == AccountInfo { + let matchers: [Cuckoo.ParameterMatcher<(AccountInfo?)>] = [wrap(matchable: accountInfo) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(_: AccountInfo?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStartSearch() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartSearch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveSelectedAccount(_ metaAccount: M1) -> Cuckoo.__DoNotUse<(MetaAccountModel), Void> where M1.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: metaAccount) { $0 }] + return cuckoo_manager.verify("didReceiveSelectedAccount(_: MetaAccountModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStopSearch() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopSearch()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStakingSettings(_ stakingSettings: M1) -> Cuckoo.__DoNotUse<(StakingAssetSettings), Void> where M1.MatchedType == StakingAssetSettings { + let matchers: [Cuckoo.ParameterMatcher<(StakingAssetSettings)>] = [wrap(matchable: stakingSettings) { $0 }] + return cuckoo_manager.verify("didReceiveStakingSettings(_: StakingAssetSettings)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReset() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didReset()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveExpansion(_ isExpanded: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] + return cuckoo_manager.verify("didReceiveExpansion(_: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveError(_ error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return cuckoo_manager.verify("didReceiveError(_: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ValidatorSearchViewProtocolStub: ValidatorSearchViewProtocol { - - - - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - - - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - - } + class StakingMainInteractorOutputProtocolStub: StakingMainInteractorOutputProtocol { @@ -36538,31 +35956,31 @@ import SoraFoundation - func didReload(_ viewModel: ValidatorSearchViewModel) { + func didReceiveAccountInfo(_ accountInfo: AccountInfo?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartSearch() { + func didReceiveSelectedAccount(_ metaAccount: MetaAccountModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStopSearch() { + func didReceiveStakingSettings(_ stakingSettings: StakingAssetSettings) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReset() { + func didReceiveExpansion(_ isExpanded: Bool) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func didReceiveError(_ error: Error) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -36570,19 +35988,19 @@ import SoraFoundation - class MockValidatorSearchInteractorInputProtocol: ValidatorSearchInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockStakingMainWireframeProtocol: StakingMainWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorSearchInteractorInputProtocol + typealias MocksType = StakingMainWireframeProtocol - typealias Stubbing = __StubbingProxy_ValidatorSearchInteractorInputProtocol - typealias Verification = __VerificationProxy_ValidatorSearchInteractorInputProtocol + typealias Stubbing = __StubbingProxy_StakingMainWireframeProtocol + typealias Verification = __VerificationProxy_StakingMainWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorSearchInteractorInputProtocol? + private var __defaultImplStub: StakingMainWireframeProtocol? - func enableDefaultImplementation(_ stub: ValidatorSearchInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: StakingMainWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -36595,114 +36013,66 @@ import SoraFoundation - func performValidatorSearch(accountId: AccountId) { + func showChainAssetSelection(from view: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate) { - return cuckoo_manager.call("performValidatorSearch(accountId: AccountId)", - parameters: (accountId), - escapingParameters: (accountId), + return cuckoo_manager.call("showChainAssetSelection(from: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate)", + parameters: (view, selectedChainAssetId, delegate), + escapingParameters: (view, selectedChainAssetId, delegate), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performValidatorSearch(accountId: accountId)) + defaultCall: __defaultImplStub!.showChainAssetSelection(from: view, selectedChainAssetId: selectedChainAssetId, delegate: delegate)) } - - struct __StubbingProxy_ValidatorSearchInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func performValidatorSearch(accountId: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountId)> where M1.MatchedType == AccountId { - let matchers: [Cuckoo.ParameterMatcher<(AccountId)>] = [wrap(matchable: accountId) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchInteractorInputProtocol.self, method: "performValidatorSearch(accountId: AccountId)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ValidatorSearchInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func performValidatorSearch(accountId: M1) -> Cuckoo.__DoNotUse<(AccountId), Void> where M1.MatchedType == AccountId { - let matchers: [Cuckoo.ParameterMatcher<(AccountId)>] = [wrap(matchable: accountId) { $0 }] - return cuckoo_manager.verify("performValidatorSearch(accountId: AccountId)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class ValidatorSearchInteractorInputProtocolStub: ValidatorSearchInteractorInputProtocol { - - - - - - func performValidatorSearch(accountId: AccountId) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) { + + return cuckoo_manager.call("showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", + parameters: (view, wallet), + escapingParameters: (view, wallet), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showWalletDetails(from: view, wallet: wallet)) + } -} - - - - class MockValidatorSearchInteractorOutputProtocol: ValidatorSearchInteractorOutputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ValidatorSearchInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_ValidatorSearchInteractorOutputProtocol - typealias Verification = __VerificationProxy_ValidatorSearchInteractorOutputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ValidatorSearchInteractorOutputProtocol? - - func enableDefaultImplementation(_ stub: ValidatorSearchInteractorOutputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + } - - - - - - - func didReceiveValidatorInfo(result: Result) { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("didReceiveValidatorInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveValidatorInfo(result: result)) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_ValidatorSearchInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingMainWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -36710,14 +36080,29 @@ import SoraFoundation } - func didReceiveValidatorInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchInteractorOutputProtocol.self, method: "didReceiveValidatorInfo(result: Result)", parameterMatchers: matchers)) + func showChainAssetSelection(from view: M1, selectedChainAssetId: M2, delegate: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainViewProtocol?, ChainAssetId?, AssetSelectionDelegate)> where M1.OptionalMatchedType == StakingMainViewProtocol, M2.OptionalMatchedType == ChainAssetId, M3.MatchedType == AssetSelectionDelegate { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?, ChainAssetId?, AssetSelectionDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: selectedChainAssetId) { $0.1 }, wrap(matchable: delegate) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainWireframeProtocol.self, method: "showChainAssetSelection(from: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate)", parameterMatchers: matchers)) + } + + func showWalletDetails(from view: M1, wallet: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, MetaAccountModel)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaAccountModel)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: wallet) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainWireframeProtocol.self, method: "showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", parameterMatchers: matchers)) + } + + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ValidatorSearchInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingMainWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -36732,15 +36117,33 @@ import SoraFoundation @discardableResult - func didReceiveValidatorInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveValidatorInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showChainAssetSelection(from view: M1, selectedChainAssetId: M2, delegate: M3) -> Cuckoo.__DoNotUse<(StakingMainViewProtocol?, ChainAssetId?, AssetSelectionDelegate), Void> where M1.OptionalMatchedType == StakingMainViewProtocol, M2.OptionalMatchedType == ChainAssetId, M3.MatchedType == AssetSelectionDelegate { + let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?, ChainAssetId?, AssetSelectionDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: selectedChainAssetId) { $0.1 }, wrap(matchable: delegate) { $0.2 }] + return cuckoo_manager.verify("showChainAssetSelection(from: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showWalletDetails(from view: M1, wallet: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, MetaAccountModel), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaAccountModel)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: wallet) { $0.1 }] + return cuckoo_manager.verify("showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ValidatorSearchInteractorOutputProtocolStub: ValidatorSearchInteractorOutputProtocol { + class StakingMainWireframeProtocolStub: StakingMainWireframeProtocol { @@ -36748,7 +36151,25 @@ import SoraFoundation - func didReceiveValidatorInfo(result: Result) { + func showChainAssetSelection(from view: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -36756,145 +36177,181 @@ import SoraFoundation - class MockValidatorSearchPresenterProtocol: ValidatorSearchPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingMainChildPresenterProtocol: StakingMainChildPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = ValidatorSearchPresenterProtocol + typealias MocksType = StakingMainChildPresenterProtocol - typealias Stubbing = __StubbingProxy_ValidatorSearchPresenterProtocol - typealias Verification = __VerificationProxy_ValidatorSearchPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingMainChildPresenterProtocol + typealias Verification = __VerificationProxy_StakingMainChildPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: ValidatorSearchPresenterProtocol? + private var __defaultImplStub: StakingMainChildPresenterProtocol? - func enableDefaultImplementation(_ stub: ValidatorSearchPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingMainChildPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } + + + func setup() { - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.setup()) } - - + + func performMainAction() { + + return cuckoo_manager.call("performMainAction()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performMainAction()) + + } - func setup() { + func performRewardInfoAction() { - return cuckoo_manager.call("setup()", + return cuckoo_manager.call("performRewardInfoAction()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.performRewardInfoAction()) } - func changeValidatorSelection(at index: Int) { + func performChangeValidatorsAction() { - return cuckoo_manager.call("changeValidatorSelection(at: Int)", - parameters: (index), - escapingParameters: (index), + return cuckoo_manager.call("performChangeValidatorsAction()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.changeValidatorSelection(at: index)) + defaultCall: __defaultImplStub!.performChangeValidatorsAction()) } - func search(for textEntry: String) { + func performSetupValidatorsForBondedAction() { - return cuckoo_manager.call("search(for: String)", - parameters: (textEntry), - escapingParameters: (textEntry), + return cuckoo_manager.call("performSetupValidatorsForBondedAction()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.search(for: textEntry)) + defaultCall: __defaultImplStub!.performSetupValidatorsForBondedAction()) } - func didSelectValidator(at index: Int) { + func performStakeMoreAction() { - return cuckoo_manager.call("didSelectValidator(at: Int)", - parameters: (index), - escapingParameters: (index), + return cuckoo_manager.call("performStakeMoreAction()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didSelectValidator(at: index)) + defaultCall: __defaultImplStub!.performStakeMoreAction()) } - func applyChanges() { + func performRedeemAction() { - return cuckoo_manager.call("applyChanges()", + return cuckoo_manager.call("performRedeemAction()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyChanges()) + defaultCall: __defaultImplStub!.performRedeemAction()) } - public func applyLocalization() { + func performRebondAction() { - return cuckoo_manager.call("applyLocalization()", + return cuckoo_manager.call("performRebondAction()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.performRebondAction()) + + } + + + + func performAnalyticsAction() { + + return cuckoo_manager.call("performAnalyticsAction()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performAnalyticsAction()) + + } + + + + func performManageAction(_ action: StakingManageOption) { + + return cuckoo_manager.call("performManageAction(_: StakingManageOption)", + parameters: (action), + escapingParameters: (action), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.performManageAction(action)) } - struct __StubbingProxy_ValidatorSearchPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingMainChildPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -36902,44 +36359,59 @@ import SoraFoundation } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } + func performMainAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performMainAction()", parameterMatchers: matchers)) + } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func performRewardInfoAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performRewardInfoAction()", parameterMatchers: matchers)) } - func changeValidatorSelection(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "changeValidatorSelection(at: Int)", parameterMatchers: matchers)) + func performChangeValidatorsAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performChangeValidatorsAction()", parameterMatchers: matchers)) } - func search(for textEntry: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: textEntry) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "search(for: String)", parameterMatchers: matchers)) + func performSetupValidatorsForBondedAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performSetupValidatorsForBondedAction()", parameterMatchers: matchers)) } - func didSelectValidator(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "didSelectValidator(at: Int)", parameterMatchers: matchers)) + func performStakeMoreAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performStakeMoreAction()", parameterMatchers: matchers)) } - func applyChanges() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func performRedeemAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "applyChanges()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performRedeemAction()", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func performRebondAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchPresenterProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performRebondAction()", parameterMatchers: matchers)) + } + + func performAnalyticsAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performAnalyticsAction()", parameterMatchers: matchers)) + } + + func performManageAction(_ action: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingManageOption)> where M1.MatchedType == StakingManageOption { + let matchers: [Cuckoo.ParameterMatcher<(StakingManageOption)>] = [wrap(matchable: action) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performManageAction(_: StakingManageOption)", parameterMatchers: matchers)) } } - struct __VerificationProxy_ValidatorSearchPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingMainChildPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -36951,11 +36423,6 @@ import SoraFoundation } - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult @@ -36965,50 +36432,63 @@ import SoraFoundation } @discardableResult - func changeValidatorSelection(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("changeValidatorSelection(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func performMainAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performMainAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func search(for textEntry: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: textEntry) { $0 }] - return cuckoo_manager.verify("search(for: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func performRewardInfoAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performRewardInfoAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didSelectValidator(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("didSelectValidator(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func performChangeValidatorsAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performChangeValidatorsAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyChanges() -> Cuckoo.__DoNotUse<(), Void> { + func performSetupValidatorsForBondedAction() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyChanges()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("performSetupValidatorsForBondedAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + func performStakeMoreAction() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("performStakeMoreAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performRedeemAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performRedeemAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performRebondAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performRebondAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performAnalyticsAction() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("performAnalyticsAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func performManageAction(_ action: M1) -> Cuckoo.__DoNotUse<(StakingManageOption), Void> where M1.MatchedType == StakingManageOption { + let matchers: [Cuckoo.ParameterMatcher<(StakingManageOption)>] = [wrap(matchable: action) { $0 }] + return cuckoo_manager.verify("performManageAction(_: StakingManageOption)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class ValidatorSearchPresenterProtocolStub: ValidatorSearchPresenterProtocol { - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - - } + class StakingMainChildPresenterProtocolStub: StakingMainChildPresenterProtocol { @@ -37022,125 +36502,56 @@ import SoraFoundation - func changeValidatorSelection(at index: Int) { + func performMainAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func search(for textEntry: String) { + func performRewardInfoAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didSelectValidator(at index: Int) { + func performChangeValidatorsAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func applyChanges() { + func performSetupValidatorsForBondedAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func performStakeMoreAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockValidatorSearchViewModelFactoryProtocol: ValidatorSearchViewModelFactoryProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = ValidatorSearchViewModelFactoryProtocol - typealias Stubbing = __StubbingProxy_ValidatorSearchViewModelFactoryProtocol - typealias Verification = __VerificationProxy_ValidatorSearchViewModelFactoryProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: ValidatorSearchViewModelFactoryProtocol? - - func enableDefaultImplementation(_ stub: ValidatorSearchViewModelFactoryProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func performRedeemAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - - - - - func createViewModel(from displayValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel { - - return cuckoo_manager.call("createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel", - parameters: (displayValidatorList, selectedValidatorList, locale), - escapingParameters: (displayValidatorList, selectedValidatorList, locale), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.createViewModel(from: displayValidatorList, selectedValidatorList: selectedValidatorList, locale: locale)) - + func performRebondAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - struct __StubbingProxy_ValidatorSearchViewModelFactoryProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func createViewModel(from displayValidatorList: M1, selectedValidatorList: M2, locale: M3) -> Cuckoo.ProtocolStubFunction<([SelectedValidatorInfo], [SelectedValidatorInfo], Locale), ValidatorSearchViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], [SelectedValidatorInfo], Locale)>] = [wrap(matchable: displayValidatorList) { $0.0 }, wrap(matchable: selectedValidatorList) { $0.1 }, wrap(matchable: locale) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockValidatorSearchViewModelFactoryProtocol.self, method: "createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_ValidatorSearchViewModelFactoryProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func createViewModel(from displayValidatorList: M1, selectedValidatorList: M2, locale: M3) -> Cuckoo.__DoNotUse<([SelectedValidatorInfo], [SelectedValidatorInfo], Locale), ValidatorSearchViewModel> where M1.MatchedType == [SelectedValidatorInfo], M2.MatchedType == [SelectedValidatorInfo], M3.MatchedType == Locale { - let matchers: [Cuckoo.ParameterMatcher<([SelectedValidatorInfo], [SelectedValidatorInfo], Locale)>] = [wrap(matchable: displayValidatorList) { $0.0 }, wrap(matchable: selectedValidatorList) { $0.1 }, wrap(matchable: locale) { $0.2 }] - return cuckoo_manager.verify("createViewModel(from: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class ValidatorSearchViewModelFactoryProtocolStub: ValidatorSearchViewModelFactoryProtocol { - - + func performAnalyticsAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func createViewModel(from displayValidatorList: [SelectedValidatorInfo], selectedValidatorList: [SelectedValidatorInfo], locale: Locale) -> ValidatorSearchViewModel { - return DefaultValueRegistry.defaultValue(for: (ValidatorSearchViewModel).self) + func performManageAction(_ action: StakingManageOption) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } } @@ -37152,19 +36563,19 @@ import Cuckoo import SoraFoundation - class MockYourValidatorListViewProtocol: YourValidatorListViewProtocol, Cuckoo.ProtocolMock { + class MockStakingPayoutConfirmationViewProtocol: StakingPayoutConfirmationViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = YourValidatorListViewProtocol + typealias MocksType = StakingPayoutConfirmationViewProtocol - typealias Stubbing = __StubbingProxy_YourValidatorListViewProtocol - typealias Verification = __VerificationProxy_YourValidatorListViewProtocol + typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationViewProtocol + typealias Verification = __VerificationProxy_StakingPayoutConfirmationViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: YourValidatorListViewProtocol? + private var __defaultImplStub: StakingPayoutConfirmationViewProtocol? - func enableDefaultImplementation(_ stub: YourValidatorListViewProtocol) { + func enableDefaultImplementation(_ stub: StakingPayoutConfirmationViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -37223,22 +36634,80 @@ import SoraFoundation } + + + var loadableContentView: UIView! { + get { + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) + } + + } + - func reload(state: YourValidatorListViewState) { + func didRecieve(viewModel: LocalizableResource) { - return cuckoo_manager.call("reload(state: YourValidatorListViewState)", - parameters: (state), - escapingParameters: (state), + return cuckoo_manager.call("didRecieve(viewModel: LocalizableResource)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload(state: state)) + defaultCall: __defaultImplStub!.didRecieve(viewModel: viewModel)) + + } + + + + func didRecieve(amountViewModel: LocalizableResource) { + + return cuckoo_manager.call("didRecieve(amountViewModel: LocalizableResource)", + parameters: (amountViewModel), + escapingParameters: (amountViewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didRecieve(amountViewModel: amountViewModel)) + + } + + + + func didReceive(feeViewModel: LocalizableResource?) { + + return cuckoo_manager.call("didReceive(feeViewModel: LocalizableResource?)", + parameters: (feeViewModel), + escapingParameters: (feeViewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(feeViewModel: feeViewModel)) } @@ -37253,12 +36722,42 @@ import SoraFoundation Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.applyLocalization()) + + } + + + + func didStartLoading() { + + return cuckoo_manager.call("didStartLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStartLoading()) + + } + + + + func didStopLoading() { + + return cuckoo_manager.call("didStopLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStopLoading()) } - struct __StubbingProxy_YourValidatorListViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingPayoutConfirmationViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -37266,34 +36765,64 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - func reload(state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(YourValidatorListViewState)> where M1.MatchedType == YourValidatorListViewState { - let matchers: [Cuckoo.ParameterMatcher<(YourValidatorListViewState)>] = [wrap(matchable: state) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListViewProtocol.self, method: "reload(state: YourValidatorListViewState)", parameterMatchers: matchers)) + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") + } + + + func didRecieve(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didRecieve(viewModel: LocalizableResource)", parameterMatchers: matchers)) + } + + func didRecieve(amountViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: amountViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didRecieve(amountViewModel: LocalizableResource)", parameterMatchers: matchers)) + } + + func didReceive(feeViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: feeViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didReceive(feeViewModel: LocalizableResource?)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + } + + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + } + + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_YourValidatorListViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingPayoutConfirmationViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -37320,12 +36849,34 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func reload(state: M1) -> Cuckoo.__DoNotUse<(YourValidatorListViewState), Void> where M1.MatchedType == YourValidatorListViewState { - let matchers: [Cuckoo.ParameterMatcher<(YourValidatorListViewState)>] = [wrap(matchable: state) { $0 }] - return cuckoo_manager.verify("reload(state: YourValidatorListViewState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didRecieve(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didRecieve(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didRecieve(amountViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: amountViewModel) { $0 }] + return cuckoo_manager.verify("didRecieve(amountViewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(feeViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: feeViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(feeViewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -37334,10 +36885,22 @@ import SoraFoundation return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } - class YourValidatorListViewProtocolStub: YourValidatorListViewProtocol { + class StakingPayoutConfirmationViewProtocolStub: StakingPayoutConfirmationViewProtocol { @@ -37367,6 +36930,24 @@ import SoraFoundation set { } } + + + + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } @@ -37374,7 +36955,19 @@ import SoraFoundation - func reload(state: YourValidatorListViewState) { + func didRecieve(viewModel: LocalizableResource) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didRecieve(amountViewModel: LocalizableResource) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceive(feeViewModel: LocalizableResource?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -37384,23 +36977,35 @@ import SoraFoundation return DefaultValueRegistry.defaultValue(for: (Void).self) } + + + func didStartLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStopLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + } - class MockYourValidatorListPresenterProtocol: YourValidatorListPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingPayoutConfirmationPresenterProtocol: StakingPayoutConfirmationPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = YourValidatorListPresenterProtocol + typealias MocksType = StakingPayoutConfirmationPresenterProtocol - typealias Stubbing = __StubbingProxy_YourValidatorListPresenterProtocol - typealias Verification = __VerificationProxy_YourValidatorListPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationPresenterProtocol + typealias Verification = __VerificationProxy_StakingPayoutConfirmationPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: YourValidatorListPresenterProtocol? + private var __defaultImplStub: StakingPayoutConfirmationPresenterProtocol? - func enableDefaultImplementation(_ stub: YourValidatorListPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingPayoutConfirmationPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -37428,51 +37033,36 @@ import SoraFoundation - func retry() { + func proceed() { - return cuckoo_manager.call("retry()", + return cuckoo_manager.call("proceed()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.retry()) - - } - - - - func didSelectValidator(viewModel: YourValidatorViewModel) { - - return cuckoo_manager.call("didSelectValidator(viewModel: YourValidatorViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didSelectValidator(viewModel: viewModel)) + defaultCall: __defaultImplStub!.proceed()) } - func changeValidators() { + func presentAccountOptions() { - return cuckoo_manager.call("changeValidators()", + return cuckoo_manager.call("presentAccountOptions()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.changeValidators()) + defaultCall: __defaultImplStub!.presentAccountOptions()) } - struct __StubbingProxy_YourValidatorListPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingPayoutConfirmationPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -37482,27 +37072,22 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func retry() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListPresenterProtocol.self, method: "retry()", parameterMatchers: matchers)) - } - - func didSelectValidator(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(YourValidatorViewModel)> where M1.MatchedType == YourValidatorViewModel { - let matchers: [Cuckoo.ParameterMatcher<(YourValidatorViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListPresenterProtocol.self, method: "didSelectValidator(viewModel: YourValidatorViewModel)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } - func changeValidators() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func presentAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListPresenterProtocol.self, method: "changeValidators()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationPresenterProtocol.self, method: "presentAccountOptions()", parameterMatchers: matchers)) } } - struct __VerificationProxy_YourValidatorListPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingPayoutConfirmationPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -37523,27 +37108,21 @@ import SoraFoundation } @discardableResult - func retry() -> Cuckoo.__DoNotUse<(), Void> { + func proceed() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("retry()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didSelectValidator(viewModel: M1) -> Cuckoo.__DoNotUse<(YourValidatorViewModel), Void> where M1.MatchedType == YourValidatorViewModel { - let matchers: [Cuckoo.ParameterMatcher<(YourValidatorViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didSelectValidator(viewModel: YourValidatorViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func changeValidators() -> Cuckoo.__DoNotUse<(), Void> { + func presentAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("changeValidators()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("presentAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class YourValidatorListPresenterProtocolStub: YourValidatorListPresenterProtocol { + class StakingPayoutConfirmationPresenterProtocolStub: StakingPayoutConfirmationPresenterProtocol { @@ -37557,19 +37136,13 @@ import SoraFoundation - func retry() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didSelectValidator(viewModel: YourValidatorViewModel) { + func proceed() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func changeValidators() { + func presentAccountOptions() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -37577,19 +37150,19 @@ import SoraFoundation - class MockYourValidatorListInteractorInputProtocol: YourValidatorListInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockStakingPayoutConfirmationInteractorInputProtocol: StakingPayoutConfirmationInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = YourValidatorListInteractorInputProtocol + typealias MocksType = StakingPayoutConfirmationInteractorInputProtocol - typealias Stubbing = __StubbingProxy_YourValidatorListInteractorInputProtocol - typealias Verification = __VerificationProxy_YourValidatorListInteractorInputProtocol + typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingPayoutConfirmationInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: YourValidatorListInteractorInputProtocol? + private var __defaultImplStub: StakingPayoutConfirmationInteractorInputProtocol? - func enableDefaultImplementation(_ stub: YourValidatorListInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: StakingPayoutConfirmationInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -37617,21 +37190,36 @@ import SoraFoundation - func refresh() { + func submitPayout() { - return cuckoo_manager.call("refresh()", + return cuckoo_manager.call("submitPayout()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.refresh()) + defaultCall: __defaultImplStub!.submitPayout()) + + } + + + + func estimateFee() { + + return cuckoo_manager.call("estimateFee()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.estimateFee()) } - struct __StubbingProxy_YourValidatorListInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingPayoutConfirmationInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -37641,17 +37229,22 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func refresh() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func submitPayout() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorInputProtocol.self, method: "refresh()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorInputProtocol.self, method: "submitPayout()", parameterMatchers: matchers)) + } + + func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) } } - struct __VerificationProxy_YourValidatorListInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingPayoutConfirmationInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -37672,15 +37265,21 @@ import SoraFoundation } @discardableResult - func refresh() -> Cuckoo.__DoNotUse<(), Void> { + func submitPayout() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("refresh()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("submitPayout()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class YourValidatorListInteractorInputProtocolStub: YourValidatorListInteractorInputProtocol { + class StakingPayoutConfirmationInteractorInputProtocolStub: StakingPayoutConfirmationInteractorInputProtocol { @@ -37694,7 +37293,13 @@ import SoraFoundation - func refresh() { + func submitPayout() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func estimateFee() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -37702,19 +37307,19 @@ import SoraFoundation - class MockYourValidatorListInteractorOutputProtocol: YourValidatorListInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockStakingPayoutConfirmationInteractorOutputProtocol: StakingPayoutConfirmationInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = YourValidatorListInteractorOutputProtocol + typealias MocksType = StakingPayoutConfirmationInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_YourValidatorListInteractorOutputProtocol - typealias Verification = __VerificationProxy_YourValidatorListInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingPayoutConfirmationInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: YourValidatorListInteractorOutputProtocol? + private var __defaultImplStub: StakingPayoutConfirmationInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: YourValidatorListInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: StakingPayoutConfirmationInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -37727,81 +37332,111 @@ import SoraFoundation - func didReceiveValidators(result: Result) { + func didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal) { - return cuckoo_manager.call("didReceiveValidators(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal)", + parameters: (account, rewardAmount), + escapingParameters: (account, rewardAmount), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveValidators(result: result)) + defaultCall: __defaultImplStub!.didRecieve(account: account, rewardAmount: rewardAmount)) } - func didReceiveController(result: Result) { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("didReceiveController(result: Result)", + return cuckoo_manager.call("didReceivePriceData(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveController(result: result)) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - func didReceiveStashItem(result: Result) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("didReceiveStashItem(result: Result)", + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - func didReceiveLedger(result: Result) { + func didReceiveFee(result: Result) { - return cuckoo_manager.call("didReceiveLedger(result: Result)", + return cuckoo_manager.call("didReceiveFee(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveLedger(result: result)) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - func didReceiveRewardDestination(result: Result) { + func didStartPayout() { - return cuckoo_manager.call("didReceiveRewardDestination(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didStartPayout()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveRewardDestination(result: result)) + defaultCall: __defaultImplStub!.didStartPayout()) + + } + + + + func didCompletePayout(txHashes: [String]) { + + return cuckoo_manager.call("didCompletePayout(txHashes: [String])", + parameters: (txHashes), + escapingParameters: (txHashes), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didCompletePayout(txHashes: txHashes)) + + } + + + + func didFailPayout(error: Error) { + + return cuckoo_manager.call("didFailPayout(error: Error)", + parameters: (error), + escapingParameters: (error), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didFailPayout(error: error)) } - struct __StubbingProxy_YourValidatorListInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingPayoutConfirmationInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -37809,34 +37444,44 @@ import SoraFoundation } - func didReceiveValidators(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveValidators(result: Result)", parameterMatchers: matchers)) + func didRecieve(account: M1, rewardAmount: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(MetaChainAccountResponse, Decimal)> where M1.MatchedType == MetaChainAccountResponse, M2.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(MetaChainAccountResponse, Decimal)>] = [wrap(matchable: account) { $0.0 }, wrap(matchable: rewardAmount) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal)", parameterMatchers: matchers)) } - func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) } - func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - func didReceiveLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveLedger(result: Result)", parameterMatchers: matchers)) + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } - func didReceiveRewardDestination(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListInteractorOutputProtocol.self, method: "didReceiveRewardDestination(result: Result)", parameterMatchers: matchers)) + func didStartPayout() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didStartPayout()", parameterMatchers: matchers)) + } + + func didCompletePayout(txHashes: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([String])> where M1.MatchedType == [String] { + let matchers: [Cuckoo.ParameterMatcher<([String])>] = [wrap(matchable: txHashes) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didCompletePayout(txHashes: [String])", parameterMatchers: matchers)) + } + + func didFailPayout(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didFailPayout(error: Error)", parameterMatchers: matchers)) } } - struct __VerificationProxy_YourValidatorListInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingPayoutConfirmationInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -37851,39 +37496,51 @@ import SoraFoundation @discardableResult - func didReceiveValidators(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveValidators(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didRecieve(account: M1, rewardAmount: M2) -> Cuckoo.__DoNotUse<(MetaChainAccountResponse, Decimal), Void> where M1.MatchedType == MetaChainAccountResponse, M2.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(MetaChainAccountResponse, Decimal)>] = [wrap(matchable: account) { $0.0 }, wrap(matchable: rewardAmount) { $0.1 }] + return cuckoo_manager.verify("didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveRewardDestination(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveRewardDestination(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStartPayout() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartPayout()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didCompletePayout(txHashes: M1) -> Cuckoo.__DoNotUse<([String]), Void> where M1.MatchedType == [String] { + let matchers: [Cuckoo.ParameterMatcher<([String])>] = [wrap(matchable: txHashes) { $0 }] + return cuckoo_manager.verify("didCompletePayout(txHashes: [String])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didFailPayout(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return cuckoo_manager.verify("didFailPayout(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class YourValidatorListInteractorOutputProtocolStub: YourValidatorListInteractorOutputProtocol { + class StakingPayoutConfirmationInteractorOutputProtocolStub: StakingPayoutConfirmationInteractorOutputProtocol { @@ -37891,88 +37548,85 @@ import SoraFoundation - func didReceiveValidators(result: Result) { + func didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveController(result: Result) { + func didReceivePriceData(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStashItem(result: Result) { + func didReceiveAccountInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveLedger(result: Result) { + func didReceiveFee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveRewardDestination(result: Result) { + func didStartPayout() { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockYourValidatorListWireframeProtocol: YourValidatorListWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = YourValidatorListWireframeProtocol - typealias Stubbing = __StubbingProxy_YourValidatorListWireframeProtocol - typealias Verification = __VerificationProxy_YourValidatorListWireframeProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - + func didCompletePayout(txHashes: [String]) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - private var __defaultImplStub: YourValidatorListWireframeProtocol? - - func enableDefaultImplementation(_ stub: YourValidatorListWireframeProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + + + func didFailPayout(error: Error) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} - - + class MockStakingPayoutConfirmationWireframeProtocol: StakingPayoutConfirmationWireframeProtocol, Cuckoo.ProtocolMock { + typealias MocksType = StakingPayoutConfirmationWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationWireframeProtocol + typealias Verification = __VerificationProxy_StakingPayoutConfirmationWireframeProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func present(_ validatorInfo: ValidatorInfoProtocol, from view: YourValidatorListViewProtocol?) { - - return cuckoo_manager.call("present(_: ValidatorInfoProtocol, from: YourValidatorListViewProtocol?)", - parameters: (validatorInfo, view), - escapingParameters: (validatorInfo, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.present(validatorInfo, from: view)) - + private var __defaultImplStub: StakingPayoutConfirmationWireframeProtocol? + + func enableDefaultImplementation(_ stub: StakingPayoutConfirmationWireframeProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func proceedToSelectValidatorsStart(from view: YourValidatorListViewProtocol?, existingBonding: ExistingBonding) { + + + + + func complete(from view: StakingPayoutConfirmationViewProtocol?) { - return cuckoo_manager.call("proceedToSelectValidatorsStart(from: YourValidatorListViewProtocol?, existingBonding: ExistingBonding)", - parameters: (view, existingBonding), - escapingParameters: (view, existingBonding), + return cuckoo_manager.call("complete(from: StakingPayoutConfirmationViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceedToSelectValidatorsStart(from: view, existingBonding: existingBonding)) + defaultCall: __defaultImplStub!.complete(from: view)) } @@ -38007,7 +37661,7 @@ import SoraFoundation } - struct __StubbingProxy_YourValidatorListWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingPayoutConfirmationWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -38015,29 +37669,24 @@ import SoraFoundation } - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorInfoProtocol, YourValidatorListViewProtocol?)> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == YourValidatorListViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, YourValidatorListViewProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListWireframeProtocol.self, method: "present(_: ValidatorInfoProtocol, from: YourValidatorListViewProtocol?)", parameterMatchers: matchers)) - } - - func proceedToSelectValidatorsStart(from view: M1, existingBonding: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(YourValidatorListViewProtocol?, ExistingBonding)> where M1.OptionalMatchedType == YourValidatorListViewProtocol, M2.MatchedType == ExistingBonding { - let matchers: [Cuckoo.ParameterMatcher<(YourValidatorListViewProtocol?, ExistingBonding)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: existingBonding) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListWireframeProtocol.self, method: "proceedToSelectValidatorsStart(from: YourValidatorListViewProtocol?, existingBonding: ExistingBonding)", parameterMatchers: matchers)) + func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingPayoutConfirmationViewProtocol?)> where M1.OptionalMatchedType == StakingPayoutConfirmationViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingPayoutConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationWireframeProtocol.self, method: "complete(from: StakingPayoutConfirmationViewProtocol?)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockYourValidatorListWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_YourValidatorListWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingPayoutConfirmationWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -38052,15 +37701,9 @@ import SoraFoundation @discardableResult - func present(_ validatorInfo: M1, from view: M2) -> Cuckoo.__DoNotUse<(ValidatorInfoProtocol, YourValidatorListViewProtocol?), Void> where M1.MatchedType == ValidatorInfoProtocol, M2.OptionalMatchedType == YourValidatorListViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorInfoProtocol, YourValidatorListViewProtocol?)>] = [wrap(matchable: validatorInfo) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("present(_: ValidatorInfoProtocol, from: YourValidatorListViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func proceedToSelectValidatorsStart(from view: M1, existingBonding: M2) -> Cuckoo.__DoNotUse<(YourValidatorListViewProtocol?, ExistingBonding), Void> where M1.OptionalMatchedType == YourValidatorListViewProtocol, M2.MatchedType == ExistingBonding { - let matchers: [Cuckoo.ParameterMatcher<(YourValidatorListViewProtocol?, ExistingBonding)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: existingBonding) { $0.1 }] - return cuckoo_manager.verify("proceedToSelectValidatorsStart(from: YourValidatorListViewProtocol?, existingBonding: ExistingBonding)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingPayoutConfirmationViewProtocol?), Void> where M1.OptionalMatchedType == StakingPayoutConfirmationViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingPayoutConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("complete(from: StakingPayoutConfirmationViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -38078,7 +37721,7 @@ import SoraFoundation } } - class YourValidatorListWireframeProtocolStub: YourValidatorListWireframeProtocol { + class StakingPayoutConfirmationWireframeProtocolStub: StakingPayoutConfirmationWireframeProtocol { @@ -38086,13 +37729,7 @@ import SoraFoundation - func present(_ validatorInfo: ValidatorInfoProtocol, from view: YourValidatorListViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func proceedToSelectValidatorsStart(from view: YourValidatorListViewProtocol?, existingBonding: ExistingBonding) { + func complete(from view: StakingPayoutConfirmationViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -38115,23 +37752,23 @@ import Cuckoo @testable import novawallet import BigInt -import CommonWallet +import Foundation import SoraFoundation - class MockStakingBondMoreViewProtocol: StakingBondMoreViewProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondConfirmationViewProtocol: StakingRebondConfirmationViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMoreViewProtocol + typealias MocksType = StakingRebondConfirmationViewProtocol - typealias Stubbing = __StubbingProxy_StakingBondMoreViewProtocol - typealias Verification = __VerificationProxy_StakingBondMoreViewProtocol + typealias Stubbing = __StubbingProxy_StakingRebondConfirmationViewProtocol + typealias Verification = __VerificationProxy_StakingRebondConfirmationViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMoreViewProtocol? + private var __defaultImplStub: StakingRebondConfirmationViewProtocol? - func enableDefaultImplementation(_ stub: StakingBondMoreViewProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondConfirmationViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -38190,37 +37827,65 @@ import SoraFoundation } + + + var loadableContentView: UIView! { + get { + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) + } + + } + - func didReceiveInput(viewModel: LocalizableResource) { + func didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel) { - return cuckoo_manager.call("didReceiveInput(viewModel: LocalizableResource)", + return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) } - func didReceiveAsset(viewModel: LocalizableResource) { + func didReceiveAmount(viewModel: LocalizableResource) { - return cuckoo_manager.call("didReceiveAsset(viewModel: LocalizableResource)", + return cuckoo_manager.call("didReceiveAmount(viewModel: LocalizableResource)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveAmount(viewModel: viewModel)) } @@ -38254,8 +37919,38 @@ import SoraFoundation } + + + func didStartLoading() { + + return cuckoo_manager.call("didStartLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStartLoading()) + + } + + + + func didStopLoading() { + + return cuckoo_manager.call("didStopLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStopLoading()) + + } + - struct __StubbingProxy_StakingBondMoreViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondConfirmationViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -38263,44 +37958,64 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreViewProtocol.self, method: "didReceiveInput(viewModel: LocalizableResource)", parameterMatchers: matchers)) + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") } - func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreViewProtocol.self, method: "didReceiveAsset(viewModel: LocalizableResource)", parameterMatchers: matchers)) + + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") + } + + + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRebondConfirmationViewModel)> where M1.MatchedType == StakingRebondConfirmationViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingRebondConfirmationViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel)", parameterMatchers: matchers)) + } + + func didReceiveAmount(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didReceiveAmount(viewModel: LocalizableResource)", parameterMatchers: matchers)) } func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + } + + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + } + + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMoreViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondConfirmationViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -38327,18 +38042,28 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveInput(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingRebondConfirmationViewModel), Void> where M1.MatchedType == StakingRebondConfirmationViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingRebondConfirmationViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveAsset(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAmount(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveAmount(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -38353,10 +38078,22 @@ import SoraFoundation return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } - class StakingBondMoreViewProtocolStub: StakingBondMoreViewProtocol { + class StakingRebondConfirmationViewProtocolStub: StakingRebondConfirmationViewProtocol { @@ -38386,6 +38123,24 @@ import SoraFoundation set { } } + + + + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } @@ -38393,13 +38148,13 @@ import SoraFoundation - func didReceiveInput(viewModel: LocalizableResource) { + func didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveAsset(viewModel: LocalizableResource) { + func didReceiveAmount(viewModel: LocalizableResource) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -38415,23 +38170,35 @@ import SoraFoundation return DefaultValueRegistry.defaultValue(for: (Void).self) } + + + func didStartLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStopLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + } - class MockStakingBondMorePresenterProtocol: StakingBondMorePresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondConfirmationPresenterProtocol: StakingRebondConfirmationPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMorePresenterProtocol + typealias MocksType = StakingRebondConfirmationPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingBondMorePresenterProtocol - typealias Verification = __VerificationProxy_StakingBondMorePresenterProtocol + typealias Stubbing = __StubbingProxy_StakingRebondConfirmationPresenterProtocol + typealias Verification = __VerificationProxy_StakingRebondConfirmationPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMorePresenterProtocol? + private var __defaultImplStub: StakingRebondConfirmationPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingBondMorePresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondConfirmationPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -38459,51 +38226,36 @@ import SoraFoundation - func handleContinueAction() { + func confirm() { - return cuckoo_manager.call("handleContinueAction()", + return cuckoo_manager.call("confirm()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.handleContinueAction()) - - } - - - - func updateAmount(_ newValue: Decimal) { - - return cuckoo_manager.call("updateAmount(_: Decimal)", - parameters: (newValue), - escapingParameters: (newValue), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.updateAmount(newValue)) + defaultCall: __defaultImplStub!.confirm()) } - func selectAmountPercentage(_ percentage: Float) { + func selectAccount() { - return cuckoo_manager.call("selectAmountPercentage(_: Float)", - parameters: (percentage), - escapingParameters: (percentage), + return cuckoo_manager.call("selectAccount()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectAmountPercentage(percentage)) + defaultCall: __defaultImplStub!.selectAccount()) } - struct __StubbingProxy_StakingBondMorePresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondConfirmationPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -38513,27 +38265,22 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMorePresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func handleContinueAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMorePresenterProtocol.self, method: "handleContinueAction()", parameterMatchers: matchers)) - } - - func updateAmount(_ newValue: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMorePresenterProtocol.self, method: "updateAmount(_: Decimal)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) } - func selectAmountPercentage(_ percentage: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Float)> where M1.MatchedType == Float { - let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMorePresenterProtocol.self, method: "selectAmountPercentage(_: Float)", parameterMatchers: matchers)) + func selectAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationPresenterProtocol.self, method: "selectAccount()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMorePresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondConfirmationPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -38554,27 +38301,21 @@ import SoraFoundation } @discardableResult - func handleContinueAction() -> Cuckoo.__DoNotUse<(), Void> { + func confirm() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handleContinueAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func updateAmount(_ newValue: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] - return cuckoo_manager.verify("updateAmount(_: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectAmountPercentage(_ percentage: M1) -> Cuckoo.__DoNotUse<(Float), Void> where M1.MatchedType == Float { - let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] - return cuckoo_manager.verify("selectAmountPercentage(_: Float)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectAccount() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingBondMorePresenterProtocolStub: StakingBondMorePresenterProtocol { + class StakingRebondConfirmationPresenterProtocolStub: StakingRebondConfirmationPresenterProtocol { @@ -38588,19 +38329,13 @@ import SoraFoundation - func handleContinueAction() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func updateAmount(_ newValue: Decimal) { + func confirm() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectAmountPercentage(_ percentage: Float) { + func selectAccount() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -38608,19 +38343,19 @@ import SoraFoundation - class MockStakingBondMoreInteractorInputProtocol: StakingBondMoreInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondConfirmationInteractorInputProtocol: StakingRebondConfirmationInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMoreInteractorInputProtocol + typealias MocksType = StakingRebondConfirmationInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingBondMoreInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingBondMoreInteractorInputProtocol + typealias Stubbing = __StubbingProxy_StakingRebondConfirmationInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingRebondConfirmationInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMoreInteractorInputProtocol? + private var __defaultImplStub: StakingRebondConfirmationInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingBondMoreInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondConfirmationInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -38648,21 +38383,36 @@ import SoraFoundation - func estimateFee() { + func submit(for amount: Decimal) { - return cuckoo_manager.call("estimateFee()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("submit(for: Decimal)", + parameters: (amount), + escapingParameters: (amount), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFee()) + defaultCall: __defaultImplStub!.submit(for: amount)) + + } + + + + func estimateFee(for amount: Decimal) { + + return cuckoo_manager.call("estimateFee(for: Decimal)", + parameters: (amount), + escapingParameters: (amount), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.estimateFee(for: amount)) } - struct __StubbingProxy_StakingBondMoreInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondConfirmationInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -38672,17 +38422,22 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) + func submit(for amount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorInputProtocol.self, method: "submit(for: Decimal)", parameterMatchers: matchers)) + } + + func estimateFee(for amount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorInputProtocol.self, method: "estimateFee(for: Decimal)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMoreInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondConfirmationInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -38703,15 +38458,21 @@ import SoraFoundation } @discardableResult - func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func submit(for amount: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] + return cuckoo_manager.verify("submit(for: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func estimateFee(for amount: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] + return cuckoo_manager.verify("estimateFee(for: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingBondMoreInteractorInputProtocolStub: StakingBondMoreInteractorInputProtocol { + class StakingRebondConfirmationInteractorInputProtocolStub: StakingRebondConfirmationInteractorInputProtocol { @@ -38725,7 +38486,13 @@ import SoraFoundation - func estimateFee() { + func submit(for amount: Decimal) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func estimateFee(for amount: Decimal) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -38733,19 +38500,19 @@ import SoraFoundation - class MockStakingBondMoreInteractorOutputProtocol: StakingBondMoreInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondConfirmationInteractorOutputProtocol: StakingRebondConfirmationInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMoreInteractorOutputProtocol + typealias MocksType = StakingRebondConfirmationInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingBondMoreInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingBondMoreInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_StakingRebondConfirmationInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingRebondConfirmationInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMoreInteractorOutputProtocol? + private var __defaultImplStub: StakingRebondConfirmationInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingBondMoreInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondConfirmationInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -38758,6 +38525,21 @@ import SoraFoundation + func didReceiveStakingLedger(result: Result) { + + return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) + + } + + + func didReceiveAccountInfo(result: Result) { return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", @@ -38803,16 +38585,16 @@ import SoraFoundation - func didReceiveStash(result: Result) { + func didReceiveController(result: Result) { - return cuckoo_manager.call("didReceiveStash(result: Result)", + return cuckoo_manager.call("didReceiveController(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStash(result: result)) + defaultCall: __defaultImplStub!.didReceiveController(result: result)) } @@ -38831,8 +38613,23 @@ import SoraFoundation } + + + func didSubmitRebonding(result: Result) { + + return cuckoo_manager.call("didSubmitRebonding(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didSubmitRebonding(result: result)) + + } + - struct __StubbingProxy_StakingBondMoreInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondConfirmationInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -38840,34 +38637,44 @@ import SoraFoundation } + func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) + } + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) } func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } - func didReceiveStash(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceiveStash(result: Result)", parameterMatchers: matchers)) + func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) } func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + } + + func didSubmitRebonding(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didSubmitRebonding(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMoreInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondConfirmationInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -38877,9 +38684,15 @@ import SoraFoundation self.callMatcher = callMatcher self.sourceLocation = sourceLocation } - - - + + + + + @discardableResult + func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } @discardableResult func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { @@ -38900,9 +38713,9 @@ import SoraFoundation } @discardableResult - func didReceiveStash(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStash(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -38911,10 +38724,16 @@ import SoraFoundation return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didSubmitRebonding(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didSubmitRebonding(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } - class StakingBondMoreInteractorOutputProtocolStub: StakingBondMoreInteractorOutputProtocol { + class StakingRebondConfirmationInteractorOutputProtocolStub: StakingRebondConfirmationInteractorOutputProtocol { @@ -38922,6 +38741,12 @@ import SoraFoundation + func didReceiveStakingLedger(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + func didReceiveAccountInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -38940,7 +38765,7 @@ import SoraFoundation - func didReceiveStash(result: Result) { + func didReceiveController(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -38950,23 +38775,29 @@ import SoraFoundation return DefaultValueRegistry.defaultValue(for: (Void).self) } + + + func didSubmitRebonding(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + } - class MockStakingBondMoreWireframeProtocol: StakingBondMoreWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondConfirmationWireframeProtocol: StakingRebondConfirmationWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMoreWireframeProtocol + typealias MocksType = StakingRebondConfirmationWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingBondMoreWireframeProtocol - typealias Verification = __VerificationProxy_StakingBondMoreWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingRebondConfirmationWireframeProtocol + typealias Verification = __VerificationProxy_StakingRebondConfirmationWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMoreWireframeProtocol? + private var __defaultImplStub: StakingRebondConfirmationWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingBondMoreWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondConfirmationWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -38979,31 +38810,16 @@ import SoraFoundation - func showConfirmation(from view: ControllerBackedProtocol?, amount: Decimal) { - - return cuckoo_manager.call("showConfirmation(from: ControllerBackedProtocol?, amount: Decimal)", - parameters: (view, amount), - escapingParameters: (view, amount), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showConfirmation(from: view, amount: amount)) - - } - - - - func close(view: ControllerBackedProtocol?) { + func complete(from view: StakingRebondConfirmationViewProtocol?) { - return cuckoo_manager.call("close(view: ControllerBackedProtocol?)", + return cuckoo_manager.call("complete(from: StakingRebondConfirmationViewProtocol?)", parameters: (view), escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(view: view)) + defaultCall: __defaultImplStub!.complete(from: view)) } @@ -39038,7 +38854,7 @@ import SoraFoundation } - struct __StubbingProxy_StakingBondMoreWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondConfirmationWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -39046,29 +38862,24 @@ import SoraFoundation } - func showConfirmation(from view: M1, amount: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, Decimal)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: amount) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreWireframeProtocol.self, method: "showConfirmation(from: ControllerBackedProtocol?, amount: Decimal)", parameterMatchers: matchers)) - } - - func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreWireframeProtocol.self, method: "close(view: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRebondConfirmationViewProtocol?)> where M1.OptionalMatchedType == StakingRebondConfirmationViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingRebondConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationWireframeProtocol.self, method: "complete(from: StakingRebondConfirmationViewProtocol?)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMoreWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondConfirmationWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -39083,15 +38894,9 @@ import SoraFoundation @discardableResult - func showConfirmation(from view: M1, amount: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, Decimal), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: amount) { $0.1 }] - return cuckoo_manager.verify("showConfirmation(from: ControllerBackedProtocol?, amount: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func close(view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(view: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingRebondConfirmationViewProtocol?), Void> where M1.OptionalMatchedType == StakingRebondConfirmationViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingRebondConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("complete(from: StakingRebondConfirmationViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -39109,7 +38914,7 @@ import SoraFoundation } } - class StakingBondMoreWireframeProtocolStub: StakingBondMoreWireframeProtocol { + class StakingRebondConfirmationWireframeProtocolStub: StakingRebondConfirmationWireframeProtocol { @@ -39117,13 +38922,7 @@ import SoraFoundation - func showConfirmation(from view: ControllerBackedProtocol?, amount: Decimal) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func close(view: ControllerBackedProtocol?) { + func complete(from view: StakingRebondConfirmationViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -39145,24 +38944,24 @@ import SoraFoundation import Cuckoo @testable import novawallet -import BigInt import CommonWallet +import Foundation import SoraFoundation - class MockStakingBondMoreConfirmationViewProtocol: StakingBondMoreConfirmationViewProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondSetupViewProtocol: StakingRebondSetupViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMoreConfirmationViewProtocol + typealias MocksType = StakingRebondSetupViewProtocol - typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationViewProtocol - typealias Verification = __VerificationProxy_StakingBondMoreConfirmationViewProtocol + typealias Stubbing = __StubbingProxy_StakingRebondSetupViewProtocol + typealias Verification = __VerificationProxy_StakingRebondSetupViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMoreConfirmationViewProtocol? + private var __defaultImplStub: StakingRebondSetupViewProtocol? - func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationViewProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondSetupViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -39221,65 +39020,22 @@ import SoraFoundation } - - - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } - - } - - func didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel) { - - return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) - - } - - - - func didReceiveAmount(viewModel: LocalizableResource) { + func didReceiveAsset(viewModel: LocalizableResource) { - return cuckoo_manager.call("didReceiveAmount(viewModel: LocalizableResource)", + return cuckoo_manager.call("didReceiveAsset(viewModel: LocalizableResource)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAmount(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) } @@ -39300,51 +39056,51 @@ import SoraFoundation - public func applyLocalization() { + func didReceiveInput(viewModel: LocalizableResource) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveInput(viewModel: LocalizableResource)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) } - func didStartLoading() { + func didReceiveTransferable(viewModel: LocalizableResource?) { - return cuckoo_manager.call("didStartLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveTransferable(viewModel: LocalizableResource?)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStartLoading()) + defaultCall: __defaultImplStub!.didReceiveTransferable(viewModel: viewModel)) } - func didStopLoading() { + public func applyLocalization() { - return cuckoo_manager.call("didStopLoading()", + return cuckoo_manager.call("applyLocalization()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopLoading()) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_StakingBondMoreConfirmationViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondSetupViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -39352,64 +39108,49 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") - } - - - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingBondMoreConfirmViewModel)> where M1.MatchedType == StakingBondMoreConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingBondMoreConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel)", parameterMatchers: matchers)) - } - - func didReceiveAmount(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didReceiveAmount(viewModel: LocalizableResource)", parameterMatchers: matchers)) + func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "didReceiveAsset(viewModel: LocalizableResource)", parameterMatchers: matchers)) } func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "didReceiveInput(viewModel: LocalizableResource)", parameterMatchers: matchers)) } - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + func didReceiveTransferable(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "didReceiveTransferable(viewModel: LocalizableResource?)", parameterMatchers: matchers)) } - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMoreConfirmationViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondSetupViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -39436,28 +39177,12 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingBondMoreConfirmViewModel), Void> where M1.MatchedType == StakingBondMoreConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingBondMoreConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAmount(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveAmount(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveAsset(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -39467,27 +39192,27 @@ import SoraFoundation } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveInput(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveTransferable(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveTransferable(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingBondMoreConfirmationViewProtocolStub: StakingBondMoreConfirmationViewProtocol { + class StakingRebondSetupViewProtocolStub: StakingRebondSetupViewProtocol { @@ -39517,24 +39242,6 @@ import SoraFoundation set { } } - - - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } @@ -39542,13 +39249,7 @@ import SoraFoundation - func didReceiveConfirmation(viewModel: StakingBondMoreConfirmViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAmount(viewModel: LocalizableResource) { + func didReceiveAsset(viewModel: LocalizableResource) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -39560,19 +39261,19 @@ import SoraFoundation - public func applyLocalization() { + func didReceiveInput(viewModel: LocalizableResource) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoading() { + func didReceiveTransferable(viewModel: LocalizableResource?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStopLoading() { + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -39580,19 +39281,19 @@ import SoraFoundation - class MockStakingBondMoreConfirmationPresenterProtocol: StakingBondMoreConfirmationPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondSetupPresenterProtocol: StakingRebondSetupPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMoreConfirmationPresenterProtocol + typealias MocksType = StakingRebondSetupPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationPresenterProtocol - typealias Verification = __VerificationProxy_StakingBondMoreConfirmationPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingRebondSetupPresenterProtocol + typealias Verification = __VerificationProxy_StakingRebondSetupPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMoreConfirmationPresenterProtocol? + private var __defaultImplStub: StakingRebondSetupPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondSetupPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -39620,36 +39321,66 @@ import SoraFoundation - func confirm() { + func selectAmountPercentage(_ percentage: Float) { - return cuckoo_manager.call("confirm()", + return cuckoo_manager.call("selectAmountPercentage(_: Float)", + parameters: (percentage), + escapingParameters: (percentage), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.selectAmountPercentage(percentage)) + + } + + + + func updateAmount(_ newValue: Decimal) { + + return cuckoo_manager.call("updateAmount(_: Decimal)", + parameters: (newValue), + escapingParameters: (newValue), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.updateAmount(newValue)) + + } + + + + func proceed() { + + return cuckoo_manager.call("proceed()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.confirm()) + defaultCall: __defaultImplStub!.proceed()) } - func selectAccount() { + func close() { - return cuckoo_manager.call("selectAccount()", + return cuckoo_manager.call("close()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectAccount()) + defaultCall: __defaultImplStub!.close()) } - struct __StubbingProxy_StakingBondMoreConfirmationPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondSetupPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -39659,22 +39390,32 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func selectAmountPercentage(_ percentage: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Float)> where M1.MatchedType == Float { + let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "selectAmountPercentage(_: Float)", parameterMatchers: matchers)) + } + + func updateAmount(_ newValue: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "updateAmount(_: Decimal)", parameterMatchers: matchers)) + } + + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } - func selectAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func close() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationPresenterProtocol.self, method: "selectAccount()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "close()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMoreConfirmationPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondSetupPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -39695,21 +39436,33 @@ import SoraFoundation } @discardableResult - func confirm() -> Cuckoo.__DoNotUse<(), Void> { + func selectAmountPercentage(_ percentage: M1) -> Cuckoo.__DoNotUse<(Float), Void> where M1.MatchedType == Float { + let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] + return cuckoo_manager.verify("selectAmountPercentage(_: Float)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func updateAmount(_ newValue: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] + return cuckoo_manager.verify("updateAmount(_: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func proceed() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectAccount() -> Cuckoo.__DoNotUse<(), Void> { + func close() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("close()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingBondMoreConfirmationPresenterProtocolStub: StakingBondMoreConfirmationPresenterProtocol { + class StakingRebondSetupPresenterProtocolStub: StakingRebondSetupPresenterProtocol { @@ -39723,13 +39476,25 @@ import SoraFoundation - func confirm() { + func selectAmountPercentage(_ percentage: Float) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectAccount() { + func updateAmount(_ newValue: Decimal) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func proceed() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func close() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -39737,19 +39502,19 @@ import SoraFoundation - class MockStakingBondMoreConfirmationInteractorInputProtocol: StakingBondMoreConfirmationInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondSetupInteractorInputProtocol: StakingRebondSetupInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMoreConfirmationInteractorInputProtocol + typealias MocksType = StakingRebondSetupInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingBondMoreConfirmationInteractorInputProtocol + typealias Stubbing = __StubbingProxy_StakingRebondSetupInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingRebondSetupInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMoreConfirmationInteractorInputProtocol? + private var __defaultImplStub: StakingRebondSetupInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondSetupInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -39777,36 +39542,21 @@ import SoraFoundation - func submit(for amount: Decimal) { - - return cuckoo_manager.call("submit(for: Decimal)", - parameters: (amount), - escapingParameters: (amount), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.submit(for: amount)) - - } - - - - func estimateFee(for amount: Decimal) { + func estimateFee() { - return cuckoo_manager.call("estimateFee(for: Decimal)", - parameters: (amount), - escapingParameters: (amount), + return cuckoo_manager.call("estimateFee()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFee(for: amount)) + defaultCall: __defaultImplStub!.estimateFee()) } - struct __StubbingProxy_StakingBondMoreConfirmationInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondSetupInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -39816,22 +39566,17 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func submit(for amount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationInteractorInputProtocol.self, method: "submit(for: Decimal)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func estimateFee(for amount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationInteractorInputProtocol.self, method: "estimateFee(for: Decimal)", parameterMatchers: matchers)) + func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMoreConfirmationInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondSetupInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -39852,21 +39597,15 @@ import SoraFoundation } @discardableResult - func submit(for amount: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] - return cuckoo_manager.verify("submit(for: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func estimateFee(for amount: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] - return cuckoo_manager.verify("estimateFee(for: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingBondMoreConfirmationInteractorInputProtocolStub: StakingBondMoreConfirmationInteractorInputProtocol { + class StakingRebondSetupInteractorInputProtocolStub: StakingRebondSetupInteractorInputProtocol { @@ -39880,13 +39619,7 @@ import SoraFoundation - func submit(for amount: Decimal) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func estimateFee(for amount: Decimal) { + func estimateFee() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -39894,19 +39627,19 @@ import SoraFoundation - class MockStakingBondMoreConfirmationOutputProtocol: StakingBondMoreConfirmationOutputProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondSetupInteractorOutputProtocol: StakingRebondSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMoreConfirmationOutputProtocol + typealias MocksType = StakingRebondSetupInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationOutputProtocol - typealias Verification = __VerificationProxy_StakingBondMoreConfirmationOutputProtocol + typealias Stubbing = __StubbingProxy_StakingRebondSetupInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingRebondSetupInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMoreConfirmationOutputProtocol? + private var __defaultImplStub: StakingRebondSetupInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationOutputProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondSetupInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -39919,61 +39652,61 @@ import SoraFoundation - func didReceiveAccountInfo(result: Result) { + func didReceiveStakingLedger(result: Result) { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) } - func didReceivePriceData(result: Result) { + func didReceiveFee(result: Result) { - return cuckoo_manager.call("didReceivePriceData(result: Result)", + return cuckoo_manager.call("didReceiveFee(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - func didReceiveFee(result: Result) { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("didReceiveFee(result: Result)", + return cuckoo_manager.call("didReceivePriceData(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - func didReceiveStash(result: Result) { + func didReceiveController(result: Result) { - return cuckoo_manager.call("didReceiveStash(result: Result)", + return cuckoo_manager.call("didReceiveController(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStash(result: result)) + defaultCall: __defaultImplStub!.didReceiveController(result: result)) } @@ -39994,21 +39727,21 @@ import SoraFoundation - func didSubmitBonding(result: Result) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("didSubmitBonding(result: Result)", + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didSubmitBonding(result: result)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - struct __StubbingProxy_StakingBondMoreConfirmationOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -40016,39 +39749,39 @@ import SoraFoundation } - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) } func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } - func didReceiveStash(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceiveStash(result: Result)", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) } func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) } - func didSubmitBonding(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationOutputProtocol.self, method: "didSubmitBonding(result: Result)", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMoreConfirmationOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -40063,15 +39796,9 @@ import SoraFoundation @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -40081,9 +39808,15 @@ import SoraFoundation } @discardableResult - func didReceiveStash(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStash(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -40093,15 +39826,15 @@ import SoraFoundation } @discardableResult - func didSubmitBonding(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didSubmitBonding(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingBondMoreConfirmationOutputProtocolStub: StakingBondMoreConfirmationOutputProtocol { + class StakingRebondSetupInteractorOutputProtocolStub: StakingRebondSetupInteractorOutputProtocol { @@ -40109,25 +39842,25 @@ import SoraFoundation - func didReceiveAccountInfo(result: Result) { + func didReceiveStakingLedger(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceivePriceData(result: Result) { + func didReceiveFee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveFee(result: Result) { + func didReceivePriceData(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStash(result: Result) { + func didReceiveController(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -40139,7 +39872,7 @@ import SoraFoundation - func didSubmitBonding(result: Result) { + func didReceiveAccountInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -40147,19 +39880,19 @@ import SoraFoundation - class MockStakingBondMoreConfirmationWireframeProtocol: StakingBondMoreConfirmationWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingRebondSetupWireframeProtocol: StakingRebondSetupWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingBondMoreConfirmationWireframeProtocol + typealias MocksType = StakingRebondSetupWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingBondMoreConfirmationWireframeProtocol - typealias Verification = __VerificationProxy_StakingBondMoreConfirmationWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingRebondSetupWireframeProtocol + typealias Verification = __VerificationProxy_StakingRebondSetupWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingBondMoreConfirmationWireframeProtocol? + private var __defaultImplStub: StakingRebondSetupWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingBondMoreConfirmationWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingRebondSetupWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -40172,16 +39905,31 @@ import SoraFoundation - func complete(from view: StakingBondMoreConfirmationViewProtocol?) { + func proceed(view parameter0: StakingRebondSetupViewProtocol?, amount parameter1: Decimal) { - return cuckoo_manager.call("complete(from: StakingBondMoreConfirmationViewProtocol?)", + return cuckoo_manager.call("proceed(view: StakingRebondSetupViewProtocol?, amount: Decimal)", + parameters: (parameter0, parameter1), + escapingParameters: (parameter0, parameter1), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.proceed(view: parameter0, amount: parameter1)) + + } + + + + func close(view: StakingRebondSetupViewProtocol?) { + + return cuckoo_manager.call("close(view: StakingRebondSetupViewProtocol?)", parameters: (view), escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.complete(from: view)) + defaultCall: __defaultImplStub!.close(view: view)) } @@ -40216,7 +39964,7 @@ import SoraFoundation } - struct __StubbingProxy_StakingBondMoreConfirmationWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRebondSetupWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -40224,24 +39972,29 @@ import SoraFoundation } - func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingBondMoreConfirmationViewProtocol?)> where M1.OptionalMatchedType == StakingBondMoreConfirmationViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingBondMoreConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationWireframeProtocol.self, method: "complete(from: StakingBondMoreConfirmationViewProtocol?)", parameterMatchers: matchers)) + func proceed(view parameter0: M1, amount parameter1: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRebondSetupViewProtocol?, Decimal)> where M1.OptionalMatchedType == StakingRebondSetupViewProtocol, M2.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(StakingRebondSetupViewProtocol?, Decimal)>] = [wrap(matchable: parameter0) { $0.0 }, wrap(matchable: parameter1) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupWireframeProtocol.self, method: "proceed(view: StakingRebondSetupViewProtocol?, amount: Decimal)", parameterMatchers: matchers)) + } + + func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRebondSetupViewProtocol?)> where M1.OptionalMatchedType == StakingRebondSetupViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingRebondSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupWireframeProtocol.self, method: "close(view: StakingRebondSetupViewProtocol?)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingBondMoreConfirmationWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingBondMoreConfirmationWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRebondSetupWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -40256,9 +40009,15 @@ import SoraFoundation @discardableResult - func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingBondMoreConfirmationViewProtocol?), Void> where M1.OptionalMatchedType == StakingBondMoreConfirmationViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingBondMoreConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("complete(from: StakingBondMoreConfirmationViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceed(view parameter0: M1, amount parameter1: M2) -> Cuckoo.__DoNotUse<(StakingRebondSetupViewProtocol?, Decimal), Void> where M1.OptionalMatchedType == StakingRebondSetupViewProtocol, M2.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(StakingRebondSetupViewProtocol?, Decimal)>] = [wrap(matchable: parameter0) { $0.0 }, wrap(matchable: parameter1) { $0.1 }] + return cuckoo_manager.verify("proceed(view: StakingRebondSetupViewProtocol?, amount: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func close(view: M1) -> Cuckoo.__DoNotUse<(StakingRebondSetupViewProtocol?), Void> where M1.OptionalMatchedType == StakingRebondSetupViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingRebondSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(view: StakingRebondSetupViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -40276,1179 +40035,784 @@ import SoraFoundation } } - class StakingBondMoreConfirmationWireframeProtocolStub: StakingBondMoreConfirmationWireframeProtocol { - - - - - - - - func complete(from view: StakingBondMoreConfirmationViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - -import Cuckoo -@testable import novawallet - -import BigInt -import Foundation - - - class MockStakingRelaychainInteractorInputProtocol: StakingRelaychainInteractorInputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRelaychainInteractorInputProtocol - - typealias Stubbing = __StubbingProxy_StakingRelaychainInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingRelaychainInteractorInputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: StakingRelaychainInteractorInputProtocol? - - func enableDefaultImplementation(_ stub: StakingRelaychainInteractorInputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - - - - - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - - } - - - struct __StubbingProxy_StakingRelaychainInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_StakingRelaychainInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class StakingRelaychainInteractorInputProtocolStub: StakingRelaychainInteractorInputProtocol { - - - - - - - - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - - - class MockStakingRelaychainInteractorOutputProtocol: StakingRelaychainInteractorOutputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRelaychainInteractorOutputProtocol - - typealias Stubbing = __StubbingProxy_StakingRelaychainInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingRelaychainInteractorOutputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: StakingRelaychainInteractorOutputProtocol? - - func enableDefaultImplementation(_ stub: StakingRelaychainInteractorOutputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - - - - - func didReceive(selectedAddress: String) { - - return cuckoo_manager.call("didReceive(selectedAddress: String)", - parameters: (selectedAddress), - escapingParameters: (selectedAddress), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(selectedAddress: selectedAddress)) - - } - - - - func didReceive(price: PriceData?) { - - return cuckoo_manager.call("didReceive(price: PriceData?)", - parameters: (price), - escapingParameters: (price), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(price: price)) - - } - - - - func didReceive(priceError: Error) { - - return cuckoo_manager.call("didReceive(priceError: Error)", - parameters: (priceError), - escapingParameters: (priceError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(priceError: priceError)) - - } - - - - func didReceive(totalReward: TotalRewardItem) { - - return cuckoo_manager.call("didReceive(totalReward: TotalRewardItem)", - parameters: (totalReward), - escapingParameters: (totalReward), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(totalReward: totalReward)) - - } - - - - func didReceive(totalRewardError: Error) { - - return cuckoo_manager.call("didReceive(totalRewardError: Error)", - parameters: (totalRewardError), - escapingParameters: (totalRewardError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(totalRewardError: totalRewardError)) - - } - - - - func didReceive(accountInfo: AccountInfo?) { - - return cuckoo_manager.call("didReceive(accountInfo: AccountInfo?)", - parameters: (accountInfo), - escapingParameters: (accountInfo), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(accountInfo: accountInfo)) - - } - - - - func didReceive(balanceError: Error) { - - return cuckoo_manager.call("didReceive(balanceError: Error)", - parameters: (balanceError), - escapingParameters: (balanceError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(balanceError: balanceError)) - - } - - - - func didReceive(calculator: RewardCalculatorEngineProtocol) { - - return cuckoo_manager.call("didReceive(calculator: RewardCalculatorEngineProtocol)", - parameters: (calculator), - escapingParameters: (calculator), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(calculator: calculator)) - - } - - - - func didReceive(calculatorError: Error) { - - return cuckoo_manager.call("didReceive(calculatorError: Error)", - parameters: (calculatorError), - escapingParameters: (calculatorError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(calculatorError: calculatorError)) - - } - - - - func didReceive(stashItem: StashItem?) { - - return cuckoo_manager.call("didReceive(stashItem: StashItem?)", - parameters: (stashItem), - escapingParameters: (stashItem), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(stashItem: stashItem)) - - } - - - - func didReceive(stashItemError: Error) { - - return cuckoo_manager.call("didReceive(stashItemError: Error)", - parameters: (stashItemError), - escapingParameters: (stashItemError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(stashItemError: stashItemError)) - - } - - - - func didReceive(ledgerInfo: StakingLedger?) { - - return cuckoo_manager.call("didReceive(ledgerInfo: StakingLedger?)", - parameters: (ledgerInfo), - escapingParameters: (ledgerInfo), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(ledgerInfo: ledgerInfo)) - - } - + class StakingRebondSetupWireframeProtocolStub: StakingRebondSetupWireframeProtocol { + - func didReceive(ledgerInfoError: Error) { - - return cuckoo_manager.call("didReceive(ledgerInfoError: Error)", - parameters: (ledgerInfoError), - escapingParameters: (ledgerInfoError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(ledgerInfoError: ledgerInfoError)) - - } + - func didReceive(nomination: Nomination?) { - - return cuckoo_manager.call("didReceive(nomination: Nomination?)", - parameters: (nomination), - escapingParameters: (nomination), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(nomination: nomination)) - + func proceed(view parameter0: StakingRebondSetupViewProtocol?, amount parameter1: Decimal) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(nominationError: Error) { - - return cuckoo_manager.call("didReceive(nominationError: Error)", - parameters: (nominationError), - escapingParameters: (nominationError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(nominationError: nominationError)) - + func close(view: StakingRebondSetupViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(validatorPrefs: ValidatorPrefs?) { - - return cuckoo_manager.call("didReceive(validatorPrefs: ValidatorPrefs?)", - parameters: (validatorPrefs), - escapingParameters: (validatorPrefs), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(validatorPrefs: validatorPrefs)) - + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(validatorError: Error) { - - return cuckoo_manager.call("didReceive(validatorError: Error)", - parameters: (validatorError), - escapingParameters: (validatorError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(validatorError: validatorError)) - + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + +import Cuckoo +@testable import novawallet + +import BigInt +import Foundation +import SoraFoundation + + + class MockStakingRedeemViewProtocol: StakingRedeemViewProtocol, Cuckoo.ProtocolMock { + typealias MocksType = StakingRedeemViewProtocol - func didReceive(eraStakersInfo: EraStakersInfo) { - - return cuckoo_manager.call("didReceive(eraStakersInfo: EraStakersInfo)", - parameters: (eraStakersInfo), - escapingParameters: (eraStakersInfo), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(eraStakersInfo: eraStakersInfo)) - - } - - + typealias Stubbing = __StubbingProxy_StakingRedeemViewProtocol + typealias Verification = __VerificationProxy_StakingRedeemViewProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func didReceive(eraStakersInfoError: Error) { - - return cuckoo_manager.call("didReceive(eraStakersInfoError: Error)", - parameters: (eraStakersInfoError), - escapingParameters: (eraStakersInfoError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(eraStakersInfoError: eraStakersInfoError)) - + private var __defaultImplStub: StakingRedeemViewProtocol? + + func enableDefaultImplementation(_ stub: StakingRedeemViewProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + - func didReceive(networkStakingInfo: NetworkStakingInfo) { - - return cuckoo_manager.call("didReceive(networkStakingInfo: NetworkStakingInfo)", - parameters: (networkStakingInfo), - escapingParameters: (networkStakingInfo), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(networkStakingInfo: networkStakingInfo)) + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } } - func didReceive(networkStakingInfoError: Error) { - - return cuckoo_manager.call("didReceive(networkStakingInfoError: Error)", - parameters: (networkStakingInfoError), - escapingParameters: (networkStakingInfoError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(networkStakingInfoError: networkStakingInfoError)) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } - func didReceive(payee: RewardDestinationArg?) { + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } - return cuckoo_manager.call("didReceive(payee: RewardDestinationArg?)", - parameters: (payee), - escapingParameters: (payee), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(payee: payee)) + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } } - func didReceive(payeeError: Error) { - - return cuckoo_manager.call("didReceive(payeeError: Error)", - parameters: (payeeError), - escapingParameters: (payeeError), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(payeeError: payeeError)) + var loadableContentView: UIView! { + get { + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) + } } - func didReceive(newChainAsset: ChainAsset) { - - return cuckoo_manager.call("didReceive(newChainAsset: ChainAsset)", - parameters: (newChainAsset), - escapingParameters: (newChainAsset), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(newChainAsset: newChainAsset)) + var shouldDisableInteractionWhenLoading: Bool { + get { + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) + } } + - - func didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod) { - - return cuckoo_manager.call("didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod)", - parameters: (subqueryRewards, period), - escapingParameters: (subqueryRewards, period), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceieve(subqueryRewards: subqueryRewards, period: period)) - - } + - func didReceiveMinNominatorBond(result: Result) { + func didReceiveConfirmation(viewModel: StakingRedeemViewModel) { - return cuckoo_manager.call("didReceiveMinNominatorBond(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingRedeemViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMinNominatorBond(result: result)) + defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) } - func didReceiveCounterForNominators(result: Result) { + func didReceiveAmount(viewModel: LocalizableResource) { - return cuckoo_manager.call("didReceiveCounterForNominators(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveAmount(viewModel: LocalizableResource)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveCounterForNominators(result: result)) + defaultCall: __defaultImplStub!.didReceiveAmount(viewModel: viewModel)) } - func didReceiveMaxNominatorsCount(result: Result) { + func didReceiveFee(viewModel: LocalizableResource?) { - return cuckoo_manager.call("didReceiveMaxNominatorsCount(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMaxNominatorsCount(result: result)) + defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) } - func didReceive(eraCountdownResult: Result) { + public func applyLocalization() { - return cuckoo_manager.call("didReceive(eraCountdownResult: Result)", - parameters: (eraCountdownResult), - escapingParameters: (eraCountdownResult), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(eraCountdownResult: eraCountdownResult)) + defaultCall: __defaultImplStub!.applyLocalization()) } - func didReceiveMaxNominatorsPerValidator(result: Result) { + func didStartLoading() { - return cuckoo_manager.call("didReceiveMaxNominatorsPerValidator(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didStartLoading()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMaxNominatorsPerValidator(result: result)) + defaultCall: __defaultImplStub!.didStartLoading()) } - func didReceiveAccount(_ account: MetaChainAccountResponse?, for accountId: AccountId) { + func didStopLoading() { - return cuckoo_manager.call("didReceiveAccount(_: MetaChainAccountResponse?, for: AccountId)", - parameters: (account, accountId), - escapingParameters: (account, accountId), + return cuckoo_manager.call("didStopLoading()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccount(account, for: accountId)) + defaultCall: __defaultImplStub!.didStopLoading()) } - struct __StubbingProxy_StakingRelaychainInteractorOutputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func didReceive(selectedAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: selectedAddress) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(selectedAddress: String)", parameterMatchers: matchers)) - } - - func didReceive(price: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PriceData?)> where M1.OptionalMatchedType == PriceData { - let matchers: [Cuckoo.ParameterMatcher<(PriceData?)>] = [wrap(matchable: price) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(price: PriceData?)", parameterMatchers: matchers)) - } - - func didReceive(priceError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: priceError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(priceError: Error)", parameterMatchers: matchers)) - } - - func didReceive(totalReward: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(TotalRewardItem)> where M1.MatchedType == TotalRewardItem { - let matchers: [Cuckoo.ParameterMatcher<(TotalRewardItem)>] = [wrap(matchable: totalReward) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(totalReward: TotalRewardItem)", parameterMatchers: matchers)) - } - - func didReceive(totalRewardError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: totalRewardError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(totalRewardError: Error)", parameterMatchers: matchers)) - } - - func didReceive(accountInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountInfo?)> where M1.OptionalMatchedType == AccountInfo { - let matchers: [Cuckoo.ParameterMatcher<(AccountInfo?)>] = [wrap(matchable: accountInfo) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(accountInfo: AccountInfo?)", parameterMatchers: matchers)) - } - - func didReceive(balanceError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: balanceError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(balanceError: Error)", parameterMatchers: matchers)) - } - - func didReceive(calculator: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RewardCalculatorEngineProtocol)> where M1.MatchedType == RewardCalculatorEngineProtocol { - let matchers: [Cuckoo.ParameterMatcher<(RewardCalculatorEngineProtocol)>] = [wrap(matchable: calculator) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(calculator: RewardCalculatorEngineProtocol)", parameterMatchers: matchers)) - } - - func didReceive(calculatorError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: calculatorError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(calculatorError: Error)", parameterMatchers: matchers)) - } - - func didReceive(stashItem: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StashItem?)> where M1.OptionalMatchedType == StashItem { - let matchers: [Cuckoo.ParameterMatcher<(StashItem?)>] = [wrap(matchable: stashItem) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(stashItem: StashItem?)", parameterMatchers: matchers)) - } - - func didReceive(stashItemError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: stashItemError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(stashItemError: Error)", parameterMatchers: matchers)) - } - - func didReceive(ledgerInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingLedger?)> where M1.OptionalMatchedType == StakingLedger { - let matchers: [Cuckoo.ParameterMatcher<(StakingLedger?)>] = [wrap(matchable: ledgerInfo) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(ledgerInfo: StakingLedger?)", parameterMatchers: matchers)) - } - - func didReceive(ledgerInfoError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: ledgerInfoError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(ledgerInfoError: Error)", parameterMatchers: matchers)) - } - - func didReceive(nomination: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Nomination?)> where M1.OptionalMatchedType == Nomination { - let matchers: [Cuckoo.ParameterMatcher<(Nomination?)>] = [wrap(matchable: nomination) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(nomination: Nomination?)", parameterMatchers: matchers)) - } - - func didReceive(nominationError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: nominationError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(nominationError: Error)", parameterMatchers: matchers)) - } - - func didReceive(validatorPrefs: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ValidatorPrefs?)> where M1.OptionalMatchedType == ValidatorPrefs { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorPrefs?)>] = [wrap(matchable: validatorPrefs) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(validatorPrefs: ValidatorPrefs?)", parameterMatchers: matchers)) - } - - func didReceive(validatorError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: validatorError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(validatorError: Error)", parameterMatchers: matchers)) - } - - func didReceive(eraStakersInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(EraStakersInfo)> where M1.MatchedType == EraStakersInfo { - let matchers: [Cuckoo.ParameterMatcher<(EraStakersInfo)>] = [wrap(matchable: eraStakersInfo) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(eraStakersInfo: EraStakersInfo)", parameterMatchers: matchers)) - } - - func didReceive(eraStakersInfoError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: eraStakersInfoError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(eraStakersInfoError: Error)", parameterMatchers: matchers)) - } - - func didReceive(networkStakingInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(NetworkStakingInfo)> where M1.MatchedType == NetworkStakingInfo { - let matchers: [Cuckoo.ParameterMatcher<(NetworkStakingInfo)>] = [wrap(matchable: networkStakingInfo) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(networkStakingInfo: NetworkStakingInfo)", parameterMatchers: matchers)) - } - - func didReceive(networkStakingInfoError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: networkStakingInfoError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(networkStakingInfoError: Error)", parameterMatchers: matchers)) - } - - func didReceive(payee: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(RewardDestinationArg?)> where M1.OptionalMatchedType == RewardDestinationArg { - let matchers: [Cuckoo.ParameterMatcher<(RewardDestinationArg?)>] = [wrap(matchable: payee) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(payee: RewardDestinationArg?)", parameterMatchers: matchers)) - } - - func didReceive(payeeError: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: payeeError) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(payeeError: Error)", parameterMatchers: matchers)) - } - - func didReceive(newChainAsset: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainAsset)> where M1.MatchedType == ChainAsset { - let matchers: [Cuckoo.ParameterMatcher<(ChainAsset)>] = [wrap(matchable: newChainAsset) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(newChainAsset: ChainAsset)", parameterMatchers: matchers)) - } - - func didReceieve(subqueryRewards: M1, period: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[SubqueryRewardItemData]?, Error>, AnalyticsPeriod)> where M1.MatchedType == Result<[SubqueryRewardItemData]?, Error>, M2.MatchedType == AnalyticsPeriod { - let matchers: [Cuckoo.ParameterMatcher<(Result<[SubqueryRewardItemData]?, Error>, AnalyticsPeriod)>] = [wrap(matchable: subqueryRewards) { $0.0 }, wrap(matchable: period) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod)", parameterMatchers: matchers)) - } - - func didReceiveMinNominatorBond(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveMinNominatorBond(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveCounterForNominators(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveCounterForNominators(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveMaxNominatorsCount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveMaxNominatorsCount(result: Result)", parameterMatchers: matchers)) - } - - func didReceive(eraCountdownResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: eraCountdownResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceive(eraCountdownResult: Result)", parameterMatchers: matchers)) - } - - func didReceiveMaxNominatorsPerValidator(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveMaxNominatorsPerValidator(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccount(_ account: M1, for accountId: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(MetaChainAccountResponse?, AccountId)> where M1.OptionalMatchedType == MetaChainAccountResponse, M2.MatchedType == AccountId { - let matchers: [Cuckoo.ParameterMatcher<(MetaChainAccountResponse?, AccountId)>] = [wrap(matchable: account) { $0.0 }, wrap(matchable: accountId) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveAccount(_: MetaChainAccountResponse?, for: AccountId)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_StakingRelaychainInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __StubbingProxy_StakingRedeemViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - @discardableResult - func didReceive(selectedAddress: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: selectedAddress) { $0 }] - return cuckoo_manager.verify("didReceive(selectedAddress: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(price: M1) -> Cuckoo.__DoNotUse<(PriceData?), Void> where M1.OptionalMatchedType == PriceData { - let matchers: [Cuckoo.ParameterMatcher<(PriceData?)>] = [wrap(matchable: price) { $0 }] - return cuckoo_manager.verify("didReceive(price: PriceData?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(priceError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: priceError) { $0 }] - return cuckoo_manager.verify("didReceive(priceError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(totalReward: M1) -> Cuckoo.__DoNotUse<(TotalRewardItem), Void> where M1.MatchedType == TotalRewardItem { - let matchers: [Cuckoo.ParameterMatcher<(TotalRewardItem)>] = [wrap(matchable: totalReward) { $0 }] - return cuckoo_manager.verify("didReceive(totalReward: TotalRewardItem)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(totalRewardError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: totalRewardError) { $0 }] - return cuckoo_manager.verify("didReceive(totalRewardError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(accountInfo: M1) -> Cuckoo.__DoNotUse<(AccountInfo?), Void> where M1.OptionalMatchedType == AccountInfo { - let matchers: [Cuckoo.ParameterMatcher<(AccountInfo?)>] = [wrap(matchable: accountInfo) { $0 }] - return cuckoo_manager.verify("didReceive(accountInfo: AccountInfo?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(balanceError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: balanceError) { $0 }] - return cuckoo_manager.verify("didReceive(balanceError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager } - @discardableResult - func didReceive(calculator: M1) -> Cuckoo.__DoNotUse<(RewardCalculatorEngineProtocol), Void> where M1.MatchedType == RewardCalculatorEngineProtocol { - let matchers: [Cuckoo.ParameterMatcher<(RewardCalculatorEngineProtocol)>] = [wrap(matchable: calculator) { $0 }] - return cuckoo_manager.verify("didReceive(calculator: RewardCalculatorEngineProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - @discardableResult - func didReceive(calculatorError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: calculatorError) { $0 }] - return cuckoo_manager.verify("didReceive(calculatorError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - @discardableResult - func didReceive(stashItem: M1) -> Cuckoo.__DoNotUse<(StashItem?), Void> where M1.OptionalMatchedType == StashItem { - let matchers: [Cuckoo.ParameterMatcher<(StashItem?)>] = [wrap(matchable: stashItem) { $0 }] - return cuckoo_manager.verify("didReceive(stashItem: StashItem?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - @discardableResult - func didReceive(stashItemError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: stashItemError) { $0 }] - return cuckoo_manager.verify("didReceive(stashItemError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - @discardableResult - func didReceive(ledgerInfo: M1) -> Cuckoo.__DoNotUse<(StakingLedger?), Void> where M1.OptionalMatchedType == StakingLedger { - let matchers: [Cuckoo.ParameterMatcher<(StakingLedger?)>] = [wrap(matchable: ledgerInfo) { $0 }] - return cuckoo_manager.verify("didReceive(ledgerInfo: StakingLedger?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") } - @discardableResult - func didReceive(ledgerInfoError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: ledgerInfoError) { $0 }] - return cuckoo_manager.verify("didReceive(ledgerInfoError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") } - @discardableResult - func didReceive(nomination: M1) -> Cuckoo.__DoNotUse<(Nomination?), Void> where M1.OptionalMatchedType == Nomination { - let matchers: [Cuckoo.ParameterMatcher<(Nomination?)>] = [wrap(matchable: nomination) { $0 }] - return cuckoo_manager.verify("didReceive(nomination: Nomination?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRedeemViewModel)> where M1.MatchedType == StakingRedeemViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingRedeemViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingRedeemViewModel)", parameterMatchers: matchers)) } - @discardableResult - func didReceive(nominationError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: nominationError) { $0 }] - return cuckoo_manager.verify("didReceive(nominationError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAmount(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didReceiveAmount(viewModel: LocalizableResource)", parameterMatchers: matchers)) } - @discardableResult - func didReceive(validatorPrefs: M1) -> Cuckoo.__DoNotUse<(ValidatorPrefs?), Void> where M1.OptionalMatchedType == ValidatorPrefs { - let matchers: [Cuckoo.ParameterMatcher<(ValidatorPrefs?)>] = [wrap(matchable: validatorPrefs) { $0 }] - return cuckoo_manager.verify("didReceive(validatorPrefs: ValidatorPrefs?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) } - @discardableResult - func didReceive(validatorError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: validatorError) { $0 }] - return cuckoo_manager.verify("didReceive(validatorError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } - @discardableResult - func didReceive(eraStakersInfo: M1) -> Cuckoo.__DoNotUse<(EraStakersInfo), Void> where M1.MatchedType == EraStakersInfo { - let matchers: [Cuckoo.ParameterMatcher<(EraStakersInfo)>] = [wrap(matchable: eraStakersInfo) { $0 }] - return cuckoo_manager.verify("didReceive(eraStakersInfo: EraStakersInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) } - @discardableResult - func didReceive(eraStakersInfoError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: eraStakersInfoError) { $0 }] - return cuckoo_manager.verify("didReceive(eraStakersInfoError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } - @discardableResult - func didReceive(networkStakingInfo: M1) -> Cuckoo.__DoNotUse<(NetworkStakingInfo), Void> where M1.MatchedType == NetworkStakingInfo { - let matchers: [Cuckoo.ParameterMatcher<(NetworkStakingInfo)>] = [wrap(matchable: networkStakingInfo) { $0 }] - return cuckoo_manager.verify("didReceive(networkStakingInfo: NetworkStakingInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + struct __VerificationProxy_StakingRedeemViewProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation } + - @discardableResult - func didReceive(networkStakingInfoError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: networkStakingInfoError) { $0 }] - return cuckoo_manager.verify("didReceive(networkStakingInfoError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceive(payee: M1) -> Cuckoo.__DoNotUse<(RewardDestinationArg?), Void> where M1.OptionalMatchedType == RewardDestinationArg { - let matchers: [Cuckoo.ParameterMatcher<(RewardDestinationArg?)>] = [wrap(matchable: payee) { $0 }] - return cuckoo_manager.verify("didReceive(payee: RewardDestinationArg?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceive(payeeError: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: payeeError) { $0 }] - return cuckoo_manager.verify("didReceive(payeeError: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceive(newChainAsset: M1) -> Cuckoo.__DoNotUse<(ChainAsset), Void> where M1.MatchedType == ChainAsset { - let matchers: [Cuckoo.ParameterMatcher<(ChainAsset)>] = [wrap(matchable: newChainAsset) { $0 }] - return cuckoo_manager.verify("didReceive(newChainAsset: ChainAsset)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceieve(subqueryRewards: M1, period: M2) -> Cuckoo.__DoNotUse<(Result<[SubqueryRewardItemData]?, Error>, AnalyticsPeriod), Void> where M1.MatchedType == Result<[SubqueryRewardItemData]?, Error>, M2.MatchedType == AnalyticsPeriod { - let matchers: [Cuckoo.ParameterMatcher<(Result<[SubqueryRewardItemData]?, Error>, AnalyticsPeriod)>] = [wrap(matchable: subqueryRewards) { $0.0 }, wrap(matchable: period) { $0.1 }] - return cuckoo_manager.verify("didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + @discardableResult - func didReceiveMinNominatorBond(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMinNominatorBond(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingRedeemViewModel), Void> where M1.MatchedType == StakingRedeemViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingRedeemViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingRedeemViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveCounterForNominators(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveCounterForNominators(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAmount(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveAmount(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveMaxNominatorsCount(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMaxNominatorsCount(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(eraCountdownResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: eraCountdownResult) { $0 }] - return cuckoo_manager.verify("didReceive(eraCountdownResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveMaxNominatorsPerValidator(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMaxNominatorsPerValidator(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveAccount(_ account: M1, for accountId: M2) -> Cuckoo.__DoNotUse<(MetaChainAccountResponse?, AccountId), Void> where M1.OptionalMatchedType == MetaChainAccountResponse, M2.MatchedType == AccountId { - let matchers: [Cuckoo.ParameterMatcher<(MetaChainAccountResponse?, AccountId)>] = [wrap(matchable: account) { $0.0 }, wrap(matchable: accountId) { $0.1 }] - return cuckoo_manager.verify("didReceiveAccount(_: MetaChainAccountResponse?, for: AccountId)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRelaychainInteractorOutputProtocolStub: StakingRelaychainInteractorOutputProtocol { - - - - - + class StakingRedeemViewProtocolStub: StakingRedeemViewProtocol { + - func didReceive(selectedAddress: String) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + } + - - func didReceive(price: PriceData?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + - - func didReceive(priceError: Error) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + } + - - func didReceive(totalReward: TotalRewardItem) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + } + - - func didReceive(totalRewardError: Error) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + } + - - func didReceive(accountInfo: AccountInfo?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceive(balanceError: Error) { + func didReceiveConfirmation(viewModel: StakingRedeemViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(calculator: RewardCalculatorEngineProtocol) { + func didReceiveAmount(viewModel: LocalizableResource) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(calculatorError: Error) { + func didReceiveFee(viewModel: LocalizableResource?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(stashItem: StashItem?) { + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(stashItemError: Error) { + func didStartLoading() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(ledgerInfo: StakingLedger?) { + func didStopLoading() { return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockStakingRedeemPresenterProtocol: StakingRedeemPresenterProtocol, Cuckoo.ProtocolMock { + typealias MocksType = StakingRedeemPresenterProtocol - func didReceive(ledgerInfoError: Error) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - + typealias Stubbing = __StubbingProxy_StakingRedeemPresenterProtocol + typealias Verification = __VerificationProxy_StakingRedeemPresenterProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func didReceive(nomination: Nomination?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + private var __defaultImplStub: StakingRedeemPresenterProtocol? + + func enableDefaultImplementation(_ stub: StakingRedeemPresenterProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func didReceive(nominationError: Error) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceive(validatorPrefs: ValidatorPrefs?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func setup() { + + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.setup()) + } - func didReceive(validatorError: Error) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func confirm() { + + return cuckoo_manager.call("confirm()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.confirm()) + } - func didReceive(eraStakersInfo: EraStakersInfo) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func selectAccount() { + + return cuckoo_manager.call("selectAccount()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.selectAccount()) + } + + struct __StubbingProxy_StakingRedeemPresenterProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + } + + func selectAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemPresenterProtocol.self, method: "selectAccount()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_StakingRedeemPresenterProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func confirm() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func selectAccount() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class StakingRedeemPresenterProtocolStub: StakingRedeemPresenterProtocol { + - func didReceive(eraStakersInfoError: Error) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceive(networkStakingInfo: NetworkStakingInfo) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(networkStakingInfoError: Error) { + func confirm() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(payee: RewardDestinationArg?) { + func selectAccount() { return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockStakingRedeemInteractorInputProtocol: StakingRedeemInteractorInputProtocol, Cuckoo.ProtocolMock { + typealias MocksType = StakingRedeemInteractorInputProtocol - func didReceive(payeeError: Error) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + typealias Stubbing = __StubbingProxy_StakingRedeemInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingRedeemInteractorInputProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: StakingRedeemInteractorInputProtocol? + + func enableDefaultImplementation(_ stub: StakingRedeemInteractorInputProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func didReceive(newChainAsset: ChainAsset) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceieve(subqueryRewards: Result<[SubqueryRewardItemData]?, Error>, period: AnalyticsPeriod) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func setup() { + + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.setup()) + } - func didReceiveMinNominatorBond(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func submitForStash(_ stashAddress: AccountAddress) { + + return cuckoo_manager.call("submitForStash(_: AccountAddress)", + parameters: (stashAddress), + escapingParameters: (stashAddress), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.submitForStash(stashAddress)) + } - func didReceiveCounterForNominators(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func estimateFeeForStash(_ stashAddress: AccountAddress) { + + return cuckoo_manager.call("estimateFeeForStash(_: AccountAddress)", + parameters: (stashAddress), + escapingParameters: (stashAddress), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.estimateFeeForStash(stashAddress)) + } + + struct __StubbingProxy_StakingRedeemInteractorInputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func submitForStash(_ stashAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: stashAddress) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorInputProtocol.self, method: "submitForStash(_: AccountAddress)", parameterMatchers: matchers)) + } + + func estimateFeeForStash(_ stashAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: stashAddress) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorInputProtocol.self, method: "estimateFeeForStash(_: AccountAddress)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_StakingRedeemInteractorInputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func submitForStash(_ stashAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: stashAddress) { $0 }] + return cuckoo_manager.verify("submitForStash(_: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func estimateFeeForStash(_ stashAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: stashAddress) { $0 }] + return cuckoo_manager.verify("estimateFeeForStash(_: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class StakingRedeemInteractorInputProtocolStub: StakingRedeemInteractorInputProtocol { + - func didReceiveMaxNominatorsCount(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceive(eraCountdownResult: Result) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveMaxNominatorsPerValidator(result: Result) { + func submitForStash(_ stashAddress: AccountAddress) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveAccount(_ account: MetaChainAccountResponse?, for accountId: AccountId) { + func estimateFeeForStash(_ stashAddress: AccountAddress) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -41456,19 +40820,19 @@ import Foundation - class MockStakingRelaychainWireframeProtocol: StakingRelaychainWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingRedeemInteractorOutputProtocol: StakingRedeemInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRelaychainWireframeProtocol + typealias MocksType = StakingRedeemInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingRelaychainWireframeProtocol - typealias Verification = __VerificationProxy_StakingRelaychainWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingRedeemInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingRedeemInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRelaychainWireframeProtocol? + private var __defaultImplStub: StakingRedeemInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingRelaychainWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingRedeemInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -41481,246 +40845,141 @@ import Foundation - func showSetupAmount(from view: StakingMainViewProtocol?) { - - return cuckoo_manager.call("showSetupAmount(from: StakingMainViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showSetupAmount(from: view)) - - } - - - - func proceedToSelectValidatorsStart(from view: StakingMainViewProtocol?, existingBonding: ExistingBonding) { - - return cuckoo_manager.call("proceedToSelectValidatorsStart(from: StakingMainViewProtocol?, existingBonding: ExistingBonding)", - parameters: (view, existingBonding), - escapingParameters: (view, existingBonding), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.proceedToSelectValidatorsStart(from: view, existingBonding: existingBonding)) - - } - - - - func showRewardDetails(from view: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal) { - - return cuckoo_manager.call("showRewardDetails(from: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal)", - parameters: (view, maxReward, avgReward), - escapingParameters: (view, maxReward, avgReward), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showRewardDetails(from: view, maxReward: maxReward, avgReward: avgReward)) - - } - - - - func showRewardPayoutsForNominator(from view: ControllerBackedProtocol?, stashAddress: AccountAddress) { - - return cuckoo_manager.call("showRewardPayoutsForNominator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", - parameters: (view, stashAddress), - escapingParameters: (view, stashAddress), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showRewardPayoutsForNominator(from: view, stashAddress: stashAddress)) - - } - - - - func showRewardPayoutsForValidator(from view: ControllerBackedProtocol?, stashAddress: AccountAddress) { - - return cuckoo_manager.call("showRewardPayoutsForValidator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", - parameters: (view, stashAddress), - escapingParameters: (view, stashAddress), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showRewardPayoutsForValidator(from: view, stashAddress: stashAddress)) - - } - - - - func showNominatorValidators(from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("showNominatorValidators(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showNominatorValidators(from: view)) - - } - - - - func showRewardDestination(from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("showRewardDestination(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showRewardDestination(from: view)) - - } - - - - func showControllerAccount(from view: ControllerBackedProtocol?) { + func didReceiveStakingLedger(result: Result) { - return cuckoo_manager.call("showControllerAccount(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showControllerAccount(from: view)) + defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) } - func showBondMore(from view: ControllerBackedProtocol?) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("showBondMore(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showBondMore(from: view)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - func showUnbond(from view: ControllerBackedProtocol?) { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("showUnbond(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showUnbond(from: view)) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - func showRedeem(from view: ControllerBackedProtocol?) { + func didReceiveExistentialDeposit(result: Result) { - return cuckoo_manager.call("showRedeem(from: ControllerBackedProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("didReceiveExistentialDeposit(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showRedeem(from: view)) + defaultCall: __defaultImplStub!.didReceiveExistentialDeposit(result: result)) } - func showRebond(from view: ControllerBackedProtocol?, option: StakingRebondOption) { + func didReceiveFee(result: Result) { - return cuckoo_manager.call("showRebond(from: ControllerBackedProtocol?, option: StakingRebondOption)", - parameters: (view, option), - escapingParameters: (view, option), + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showRebond(from: view, option: option)) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - func showAnalytics(from view: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode) { + func didReceiveController(result: Result) { - return cuckoo_manager.call("showAnalytics(from: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode)", - parameters: (view, mode), - escapingParameters: (view, mode), + return cuckoo_manager.call("didReceiveController(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showAnalytics(from: view, mode: mode)) + defaultCall: __defaultImplStub!.didReceiveController(result: result)) } - func showYourValidatorInfo(_ stashAddress: AccountAddress, from view: ControllerBackedProtocol?) { + func didReceiveStashItem(result: Result) { - return cuckoo_manager.call("showYourValidatorInfo(_: AccountAddress, from: ControllerBackedProtocol?)", - parameters: (stashAddress, view), - escapingParameters: (stashAddress, view), + return cuckoo_manager.call("didReceiveStashItem(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showYourValidatorInfo(stashAddress, from: view)) + defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func didReceiveActiveEra(result: Result) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("didReceiveActiveEra(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.didReceiveActiveEra(result: result)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didSubmitRedeeming(result: Result) { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("didSubmitRedeeming(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.didSubmitRedeeming(result: result)) } - struct __StubbingProxy_StakingRelaychainWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRedeemInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -41728,89 +40987,54 @@ import Foundation } - func showSetupAmount(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainViewProtocol?)> where M1.OptionalMatchedType == StakingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showSetupAmount(from: StakingMainViewProtocol?)", parameterMatchers: matchers)) - } - - func proceedToSelectValidatorsStart(from view: M1, existingBonding: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainViewProtocol?, ExistingBonding)> where M1.OptionalMatchedType == StakingMainViewProtocol, M2.MatchedType == ExistingBonding { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?, ExistingBonding)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: existingBonding) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "proceedToSelectValidatorsStart(from: StakingMainViewProtocol?, existingBonding: ExistingBonding)", parameterMatchers: matchers)) - } - - func showRewardDetails(from view: M1, maxReward: M2, avgReward: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, Decimal, Decimal)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == Decimal, M3.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, Decimal, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: maxReward) { $0.1 }, wrap(matchable: avgReward) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRewardDetails(from: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal)", parameterMatchers: matchers)) - } - - func showRewardPayoutsForNominator(from view: M1, stashAddress: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, AccountAddress)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AccountAddress)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: stashAddress) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRewardPayoutsForNominator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", parameterMatchers: matchers)) - } - - func showRewardPayoutsForValidator(from view: M1, stashAddress: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, AccountAddress)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AccountAddress)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: stashAddress) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRewardPayoutsForValidator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", parameterMatchers: matchers)) - } - - func showNominatorValidators(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showNominatorValidators(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func showRewardDestination(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRewardDestination(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func showControllerAccount(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showControllerAccount(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) } - func showBondMore(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showBondMore(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - func showUnbond(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showUnbond(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) } - func showRedeem(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRedeem(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveExistentialDeposit(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveExistentialDeposit(result: Result)", parameterMatchers: matchers)) } - func showRebond(from view: M1, option: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, StakingRebondOption)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == StakingRebondOption { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, StakingRebondOption)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: option) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showRebond(from: ControllerBackedProtocol?, option: StakingRebondOption)", parameterMatchers: matchers)) + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } - func showAnalytics(from view: M1, mode: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, AnalyticsContainerViewMode)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AnalyticsContainerViewMode { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AnalyticsContainerViewMode)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: mode) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showAnalytics(from: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode)", parameterMatchers: matchers)) + func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) } - func showYourValidatorInfo(_ stashAddress: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress, ControllerBackedProtocol?)> where M1.MatchedType == AccountAddress, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress, ControllerBackedProtocol?)>] = [wrap(matchable: stashAddress) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showYourValidatorInfo(_: AccountAddress, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveActiveEra(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveActiveEra(result: Result)", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didSubmitRedeeming(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didSubmitRedeeming(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRelaychainWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRedeemInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -41825,87 +41049,238 @@ import Foundation @discardableResult - func showSetupAmount(from view: M1) -> Cuckoo.__DoNotUse<(StakingMainViewProtocol?), Void> where M1.OptionalMatchedType == StakingMainViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showSetupAmount(from: StakingMainViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceedToSelectValidatorsStart(from view: M1, existingBonding: M2) -> Cuckoo.__DoNotUse<(StakingMainViewProtocol?, ExistingBonding), Void> where M1.OptionalMatchedType == StakingMainViewProtocol, M2.MatchedType == ExistingBonding { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?, ExistingBonding)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: existingBonding) { $0.1 }] - return cuckoo_manager.verify("proceedToSelectValidatorsStart(from: StakingMainViewProtocol?, existingBonding: ExistingBonding)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showRewardDetails(from view: M1, maxReward: M2, avgReward: M3) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, Decimal, Decimal), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == Decimal, M3.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, Decimal, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: maxReward) { $0.1 }, wrap(matchable: avgReward) { $0.2 }] - return cuckoo_manager.verify("showRewardDetails(from: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showRewardPayoutsForNominator(from view: M1, stashAddress: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, AccountAddress), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AccountAddress)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: stashAddress) { $0.1 }] - return cuckoo_manager.verify("showRewardPayoutsForNominator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveExistentialDeposit(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveExistentialDeposit(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showRewardPayoutsForValidator(from view: M1, stashAddress: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, AccountAddress), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AccountAddress)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: stashAddress) { $0.1 }] - return cuckoo_manager.verify("showRewardPayoutsForValidator(from: ControllerBackedProtocol?, stashAddress: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showNominatorValidators(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showNominatorValidators(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showRewardDestination(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showRewardDestination(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showControllerAccount(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showControllerAccount(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveActiveEra(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveActiveEra(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showBondMore(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showBondMore(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didSubmitRedeeming(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didSubmitRedeeming(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - @discardableResult - func showUnbond(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showUnbond(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } +} + + class StakingRedeemInteractorOutputProtocolStub: StakingRedeemInteractorOutputProtocol { + + + + + + + + func didReceiveStakingLedger(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveAccountInfo(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceivePriceData(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveExistentialDeposit(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveFee(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveController(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveStashItem(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveActiveEra(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didSubmitRedeeming(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + + + class MockStakingRedeemWireframeProtocol: StakingRedeemWireframeProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = StakingRedeemWireframeProtocol + + typealias Stubbing = __StubbingProxy_StakingRedeemWireframeProtocol + typealias Verification = __VerificationProxy_StakingRedeemWireframeProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: StakingRedeemWireframeProtocol? + + func enableDefaultImplementation(_ stub: StakingRedeemWireframeProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + + + + + + + + + func complete(from view: StakingRedeemViewProtocol?) { + + return cuckoo_manager.call("complete(from: StakingRedeemViewProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.complete(from: view)) + + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + + } + + + struct __StubbingProxy_StakingRedeemWireframeProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRedeemViewProtocol?)> where M1.OptionalMatchedType == StakingRedeemViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingRedeemViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemWireframeProtocol.self, method: "complete(from: StakingRedeemViewProtocol?)", parameterMatchers: matchers)) } - @discardableResult - func showRedeem(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("showRedeem(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - @discardableResult - func showRebond(from view: M1, option: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, StakingRebondOption), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == StakingRebondOption { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, StakingRebondOption)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: option) { $0.1 }] - return cuckoo_manager.verify("showRebond(from: ControllerBackedProtocol?, option: StakingRebondOption)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - @discardableResult - func showAnalytics(from view: M1, mode: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, AnalyticsContainerViewMode), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AnalyticsContainerViewMode { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AnalyticsContainerViewMode)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: mode) { $0.1 }] - return cuckoo_manager.verify("showAnalytics(from: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + struct __VerificationProxy_StakingRedeemWireframeProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation } + + + @discardableResult - func showYourValidatorInfo(_ stashAddress: M1, from view: M2) -> Cuckoo.__DoNotUse<(AccountAddress, ControllerBackedProtocol?), Void> where M1.MatchedType == AccountAddress, M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress, ControllerBackedProtocol?)>] = [wrap(matchable: stashAddress) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("showYourValidatorInfo(_: AccountAddress, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingRedeemViewProtocol?), Void> where M1.OptionalMatchedType == StakingRedeemViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingRedeemViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("complete(from: StakingRedeemViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -41923,7 +41298,7 @@ import Foundation } } - class StakingRelaychainWireframeProtocolStub: StakingRelaychainWireframeProtocol { + class StakingRedeemWireframeProtocolStub: StakingRedeemWireframeProtocol { @@ -41931,85 +41306,7 @@ import Foundation - func showSetupAmount(from view: StakingMainViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func proceedToSelectValidatorsStart(from view: StakingMainViewProtocol?, existingBonding: ExistingBonding) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showRewardDetails(from view: ControllerBackedProtocol?, maxReward: Decimal, avgReward: Decimal) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showRewardPayoutsForNominator(from view: ControllerBackedProtocol?, stashAddress: AccountAddress) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showRewardPayoutsForValidator(from view: ControllerBackedProtocol?, stashAddress: AccountAddress) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showNominatorValidators(from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showRewardDestination(from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showControllerAccount(from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showBondMore(from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showUnbond(from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showRedeem(from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showRebond(from view: ControllerBackedProtocol?, option: StakingRebondOption) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showAnalytics(from view: ControllerBackedProtocol?, mode: AnalyticsContainerViewMode) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showYourValidatorInfo(_ stashAddress: AccountAddress, from view: ControllerBackedProtocol?) { + func complete(from view: StakingRedeemViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -42031,25 +41328,22 @@ import Foundation import Cuckoo @testable import novawallet -import BigInt -import CommonWallet -import Foundation import SoraFoundation - class MockStakingMainViewProtocol: StakingMainViewProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardDestConfirmViewProtocol: StakingRewardDestConfirmViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingMainViewProtocol + typealias MocksType = StakingRewardDestConfirmViewProtocol - typealias Stubbing = __StubbingProxy_StakingMainViewProtocol - typealias Verification = __VerificationProxy_StakingMainViewProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmViewProtocol + typealias Verification = __VerificationProxy_StakingRewardDestConfirmViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingMainViewProtocol? + private var __defaultImplStub: StakingRewardDestConfirmViewProtocol? - func enableDefaultImplementation(_ stub: StakingMainViewProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardDestConfirmViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -42108,102 +41402,115 @@ import SoraFoundation } - - + var loadableContentView: UIView! { + get { + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) + } + + } - func didReceive(viewModel: StakingMainViewModel) { - - return cuckoo_manager.call("didReceive(viewModel: StakingMainViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceive(viewModel: viewModel)) + + var shouldDisableInteractionWhenLoading: Bool { + get { + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) + } } + + + + - func didRecieveNetworkStakingInfo(viewModel: LocalizableResource?) { + func didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel) { - return cuckoo_manager.call("didRecieveNetworkStakingInfo(viewModel: LocalizableResource?)", + return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didRecieveNetworkStakingInfo(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) } - func didReceiveStakingState(viewModel: StakingViewState) { + func didReceiveFee(viewModel: LocalizableResource?) { - return cuckoo_manager.call("didReceiveStakingState(viewModel: StakingViewState)", + return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", parameters: (viewModel), escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStakingState(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) } - func expandNetworkInfoView(_ isExpanded: Bool) { + public func applyLocalization() { - return cuckoo_manager.call("expandNetworkInfoView(_: Bool)", - parameters: (isExpanded), - escapingParameters: (isExpanded), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.expandNetworkInfoView(isExpanded)) + defaultCall: __defaultImplStub!.applyLocalization()) } - func didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol) { + func didStartLoading() { - return cuckoo_manager.call("didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didStartLoading()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStatics(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didStartLoading()) } - public func applyLocalization() { + func didStopLoading() { - return cuckoo_manager.call("applyLocalization()", + return cuckoo_manager.call("didStopLoading()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.didStopLoading()) } - struct __StubbingProxy_StakingMainViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDestConfirmViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -42211,54 +41518,59 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - func didReceive(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainViewModel)> where M1.MatchedType == StakingMainViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "didReceive(viewModel: StakingMainViewModel)", parameterMatchers: matchers)) + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") } - func didRecieveNetworkStakingInfo(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "didRecieveNetworkStakingInfo(viewModel: LocalizableResource?)", parameterMatchers: matchers)) - } - func didReceiveStakingState(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingViewState)> where M1.MatchedType == StakingViewState { - let matchers: [Cuckoo.ParameterMatcher<(StakingViewState)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "didReceiveStakingState(viewModel: StakingViewState)", parameterMatchers: matchers)) + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") } - func expandNetworkInfoView(_ isExpanded: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "expandNetworkInfoView(_: Bool)", parameterMatchers: matchers)) + + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRewardDestConfirmViewModel)> where M1.MatchedType == StakingRewardDestConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel)", parameterMatchers: matchers)) } - func didReceiveStatics(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainStaticViewModelProtocol)> where M1.MatchedType == StakingMainStaticViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainStaticViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol)", parameterMatchers: matchers)) + func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + } + + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + } + + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingMainViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDestConfirmViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -42285,48 +41597,52 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } - - @discardableResult - func didReceive(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingMainViewModel), Void> where M1.MatchedType == StakingMainViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceive(viewModel: StakingMainViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + @discardableResult - func didRecieveNetworkStakingInfo(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didRecieveNetworkStakingInfo(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingRewardDestConfirmViewModel), Void> where M1.MatchedType == StakingRewardDestConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStakingState(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingViewState), Void> where M1.MatchedType == StakingViewState { - let matchers: [Cuckoo.ParameterMatcher<(StakingViewState)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveStakingState(viewModel: StakingViewState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func expandNetworkInfoView(_ isExpanded: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] - return cuckoo_manager.verify("expandNetworkInfoView(_: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStatics(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingMainStaticViewModelProtocol), Void> where M1.MatchedType == StakingMainStaticViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainStaticViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingMainViewProtocolStub: StakingMainViewProtocol { + class StakingRewardDestConfirmViewProtocolStub: StakingRewardDestConfirmViewProtocol { @@ -42356,44 +41672,245 @@ import SoraFoundation set { } } + + + + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + + + + + + + + func didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveFee(viewModel: LocalizableResource?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + public func applyLocalization() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStartLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStopLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + + + class MockStakingRewardDestConfirmPresenterProtocol: StakingRewardDestConfirmPresenterProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = StakingRewardDestConfirmPresenterProtocol + + typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmPresenterProtocol + typealias Verification = __VerificationProxy_StakingRewardDestConfirmPresenterProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: StakingRewardDestConfirmPresenterProtocol? + + func enableDefaultImplementation(_ stub: StakingRewardDestConfirmPresenterProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + + + + + + + + + func setup() { + + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.setup()) + + } + + + + func confirm() { + + return cuckoo_manager.call("confirm()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.confirm()) + + } + + + + func presentSenderAccountOptions() { + + return cuckoo_manager.call("presentSenderAccountOptions()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentSenderAccountOptions()) + + } + + + + func presentPayoutAccountOptions() { + + return cuckoo_manager.call("presentPayoutAccountOptions()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentPayoutAccountOptions()) + + } + struct __StubbingProxy_StakingRewardDestConfirmPresenterProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + } + + func presentSenderAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmPresenterProtocol.self, method: "presentSenderAccountOptions()", parameterMatchers: matchers)) + } + + func presentPayoutAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmPresenterProtocol.self, method: "presentPayoutAccountOptions()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_StakingRewardDestConfirmPresenterProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func confirm() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentSenderAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentSenderAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentPayoutAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentPayoutAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class StakingRewardDestConfirmPresenterProtocolStub: StakingRewardDestConfirmPresenterProtocol { - - - func didReceive(viewModel: StakingMainViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didRecieveNetworkStakingInfo(viewModel: LocalizableResource?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func didReceiveStakingState(viewModel: StakingViewState) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func expandNetworkInfoView(_ isExpanded: Bool) { + func confirm() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStatics(viewModel: StakingMainStaticViewModelProtocol) { + func presentSenderAccountOptions() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func presentPayoutAccountOptions() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -42401,19 +41918,19 @@ import SoraFoundation - class MockStakingMainPresenterProtocol: StakingMainPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardDestConfirmInteractorInputProtocol: StakingRewardDestConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingMainPresenterProtocol + typealias MocksType = StakingRewardDestConfirmInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingMainPresenterProtocol - typealias Verification = __VerificationProxy_StakingMainPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingRewardDestConfirmInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingMainPresenterProtocol? + private var __defaultImplStub: StakingRewardDestConfirmInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingMainPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardDestConfirmInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -42441,186 +41958,238 @@ import SoraFoundation - func performAssetSelection() { + func estimateFee(for rewardDestination: RewardDestination, stashItem: StashItem) { - return cuckoo_manager.call("performAssetSelection()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("estimateFee(for: RewardDestination, stashItem: StashItem)", + parameters: (rewardDestination, stashItem), + escapingParameters: (rewardDestination, stashItem), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performAssetSelection()) + defaultCall: __defaultImplStub!.estimateFee(for: rewardDestination, stashItem: stashItem)) } - func performMainAction() { + func submit(rewardDestination: RewardDestination, for stashItem: StashItem) { - return cuckoo_manager.call("performMainAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("submit(rewardDestination: RewardDestination, for: StashItem)", + parameters: (rewardDestination, stashItem), + escapingParameters: (rewardDestination, stashItem), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performMainAction()) + defaultCall: __defaultImplStub!.submit(rewardDestination: rewardDestination, for: stashItem)) } + + struct __StubbingProxy_StakingRewardDestConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func estimateFee(for rewardDestination: M1, stashItem: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(RewardDestination, StashItem)> where M1.MatchedType == RewardDestination, M2.MatchedType == StashItem { + let matchers: [Cuckoo.ParameterMatcher<(RewardDestination, StashItem)>] = [wrap(matchable: rewardDestination) { $0.0 }, wrap(matchable: stashItem) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorInputProtocol.self, method: "estimateFee(for: RewardDestination, stashItem: StashItem)", parameterMatchers: matchers)) + } + + func submit(rewardDestination: M1, for stashItem: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(RewardDestination, StashItem)> where M1.MatchedType == RewardDestination, M2.MatchedType == StashItem { + let matchers: [Cuckoo.ParameterMatcher<(RewardDestination, StashItem)>] = [wrap(matchable: rewardDestination) { $0.0 }, wrap(matchable: stashItem) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorInputProtocol.self, method: "submit(rewardDestination: RewardDestination, for: StashItem)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_StakingRewardDestConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func estimateFee(for rewardDestination: M1, stashItem: M2) -> Cuckoo.__DoNotUse<(RewardDestination, StashItem), Void> where M1.MatchedType == RewardDestination, M2.MatchedType == StashItem { + let matchers: [Cuckoo.ParameterMatcher<(RewardDestination, StashItem)>] = [wrap(matchable: rewardDestination) { $0.0 }, wrap(matchable: stashItem) { $0.1 }] + return cuckoo_manager.verify("estimateFee(for: RewardDestination, stashItem: StashItem)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func submit(rewardDestination: M1, for stashItem: M2) -> Cuckoo.__DoNotUse<(RewardDestination, StashItem), Void> where M1.MatchedType == RewardDestination, M2.MatchedType == StashItem { + let matchers: [Cuckoo.ParameterMatcher<(RewardDestination, StashItem)>] = [wrap(matchable: rewardDestination) { $0.0 }, wrap(matchable: stashItem) { $0.1 }] + return cuckoo_manager.verify("submit(rewardDestination: RewardDestination, for: StashItem)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class StakingRewardDestConfirmInteractorInputProtocolStub: StakingRewardDestConfirmInteractorInputProtocol { + - func performAccountAction() { - - return cuckoo_manager.call("performAccountAction()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.performAccountAction()) - + + + + + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performRewardInfoAction() { - - return cuckoo_manager.call("performRewardInfoAction()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.performRewardInfoAction()) - + func estimateFee(for rewardDestination: RewardDestination, stashItem: StashItem) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performChangeValidatorsAction() { - - return cuckoo_manager.call("performChangeValidatorsAction()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.performChangeValidatorsAction()) - + func submit(rewardDestination: RewardDestination, for stashItem: StashItem) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockStakingRewardDestConfirmInteractorOutputProtocol: StakingRewardDestConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { + typealias MocksType = StakingRewardDestConfirmInteractorOutputProtocol - func performSetupValidatorsForBondedAction() { - - return cuckoo_manager.call("performSetupValidatorsForBondedAction()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.performSetupValidatorsForBondedAction()) - + typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingRewardDestConfirmInteractorOutputProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: StakingRewardDestConfirmInteractorOutputProtocol? + + func enableDefaultImplementation(_ stub: StakingRewardDestConfirmInteractorOutputProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + + + - func performStakeMoreAction() { + + + func didReceiveFee(result: Result) { - return cuckoo_manager.call("performStakeMoreAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performStakeMoreAction()) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - func performRedeemAction() { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("performRedeemAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performRedeemAction()) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - func performRebondAction() { + func didReceiveStashItem(result: Result) { - return cuckoo_manager.call("performRebondAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveStashItem(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performRebondAction()) + defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) } - func performAnalyticsAction() { + func didReceiveController(result: Result) { - return cuckoo_manager.call("performAnalyticsAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveController(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performAnalyticsAction()) + defaultCall: __defaultImplStub!.didReceiveController(result: result)) } - func networkInfoViewDidChangeExpansion(isExpanded: Bool) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("networkInfoViewDidChangeExpansion(isExpanded: Bool)", - parameters: (isExpanded), - escapingParameters: (isExpanded), + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.networkInfoViewDidChangeExpansion(isExpanded: isExpanded)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - func performManageAction(_ action: StakingManageOption) { + func didSubmitRewardDest(result: Result) { - return cuckoo_manager.call("performManageAction(_: StakingManageOption)", - parameters: (action), - escapingParameters: (action), + return cuckoo_manager.call("didSubmitRewardDest(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performManageAction(action)) + defaultCall: __defaultImplStub!.didSubmitRewardDest(result: result)) } - struct __StubbingProxy_StakingMainPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDestConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -42628,74 +42197,39 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func performAssetSelection() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performAssetSelection()", parameterMatchers: matchers)) - } - - func performMainAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performMainAction()", parameterMatchers: matchers)) - } - - func performAccountAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performAccountAction()", parameterMatchers: matchers)) - } - - func performRewardInfoAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performRewardInfoAction()", parameterMatchers: matchers)) - } - - func performChangeValidatorsAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performChangeValidatorsAction()", parameterMatchers: matchers)) - } - - func performSetupValidatorsForBondedAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performSetupValidatorsForBondedAction()", parameterMatchers: matchers)) - } - - func performStakeMoreAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performStakeMoreAction()", parameterMatchers: matchers)) + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } - func performRedeemAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performRedeemAction()", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) } - func performRebondAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performRebondAction()", parameterMatchers: matchers)) + func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) } - func performAnalyticsAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performAnalyticsAction()", parameterMatchers: matchers)) + func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) } - func networkInfoViewDidChangeExpansion(isExpanded: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "networkInfoViewDidChangeExpansion(isExpanded: Bool)", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - func performManageAction(_ action: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingManageOption)> where M1.MatchedType == StakingManageOption { - let matchers: [Cuckoo.ParameterMatcher<(StakingManageOption)>] = [wrap(matchable: action) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainPresenterProtocol.self, method: "performManageAction(_: StakingManageOption)", parameterMatchers: matchers)) + func didSubmitRewardDest(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didSubmitRewardDest(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingMainPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDestConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -42710,87 +42244,220 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performAssetSelection() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performAssetSelection()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performMainAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performMainAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performAccountAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performAccountAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performRewardInfoAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performRewardInfoAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performChangeValidatorsAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performChangeValidatorsAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didSubmitRewardDest(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didSubmitRewardDest(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - @discardableResult - func performSetupValidatorsForBondedAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performSetupValidatorsForBondedAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } +} + + class StakingRewardDestConfirmInteractorOutputProtocolStub: StakingRewardDestConfirmInteractorOutputProtocol { + + + + + + + + func didReceiveFee(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceivePriceData(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveStashItem(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveController(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveAccountInfo(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didSubmitRewardDest(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + + + class MockStakingRewardDestConfirmWireframeProtocol: StakingRewardDestConfirmWireframeProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = StakingRewardDestConfirmWireframeProtocol + + typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmWireframeProtocol + typealias Verification = __VerificationProxy_StakingRewardDestConfirmWireframeProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: StakingRewardDestConfirmWireframeProtocol? + + func enableDefaultImplementation(_ stub: StakingRewardDestConfirmWireframeProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + + + + + + + + + func complete(from view: StakingRewardDestConfirmViewProtocol?) { + + return cuckoo_manager.call("complete(from: StakingRewardDestConfirmViewProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.complete(from: view)) + + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + + } + + + struct __StubbingProxy_StakingRewardDestConfirmWireframeProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager } - @discardableResult - func performStakeMoreAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performStakeMoreAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRewardDestConfirmViewProtocol?)> where M1.OptionalMatchedType == StakingRewardDestConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmWireframeProtocol.self, method: "complete(from: StakingRewardDestConfirmViewProtocol?)", parameterMatchers: matchers)) } - @discardableResult - func performRedeemAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performRedeemAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - @discardableResult - func performRebondAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performRebondAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + struct __VerificationProxy_StakingRewardDestConfirmWireframeProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation } + + + @discardableResult - func performAnalyticsAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performAnalyticsAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingRewardDestConfirmViewProtocol?), Void> where M1.OptionalMatchedType == StakingRewardDestConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("complete(from: StakingRewardDestConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func networkInfoViewDidChangeExpansion(isExpanded: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] - return cuckoo_manager.verify("networkInfoViewDidChangeExpansion(isExpanded: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performManageAction(_ action: M1) -> Cuckoo.__DoNotUse<(StakingManageOption), Void> where M1.MatchedType == StakingManageOption { - let matchers: [Cuckoo.ParameterMatcher<(StakingManageOption)>] = [wrap(matchable: action) { $0 }] - return cuckoo_manager.verify("performManageAction(_: StakingManageOption)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingMainPresenterProtocolStub: StakingMainPresenterProtocol { + class StakingRewardDestConfirmWireframeProtocolStub: StakingRewardDestConfirmWireframeProtocol { @@ -42798,156 +42465,169 @@ import SoraFoundation - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func performAssetSelection() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func performMainAction() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func performAccountAction() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func performRewardInfoAction() { + func complete(from view: StakingRewardDestConfirmViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performChangeValidatorsAction() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performSetupValidatorsForBondedAction() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + +import Cuckoo +@testable import novawallet + +import Foundation +import SoraFoundation + + + class MockStakingRewardDestSetupViewProtocol: StakingRewardDestSetupViewProtocol, Cuckoo.ProtocolMock { + typealias MocksType = StakingRewardDestSetupViewProtocol - func performStakeMoreAction() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - + typealias Stubbing = __StubbingProxy_StakingRewardDestSetupViewProtocol + typealias Verification = __VerificationProxy_StakingRewardDestSetupViewProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func performRedeemAction() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + private var __defaultImplStub: StakingRewardDestSetupViewProtocol? + + func enableDefaultImplementation(_ stub: StakingRewardDestSetupViewProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } - - - func performRebondAction() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func performAnalyticsAction() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + } - func networkInfoViewDidChangeExpansion(isExpanded: Bool) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } + } - func performManageAction(_ action: StakingManageOption) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } + + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } + } -} - - - - class MockStakingMainInteractorInputProtocol: StakingMainInteractorInputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingMainInteractorInputProtocol - - typealias Stubbing = __StubbingProxy_StakingMainInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingMainInteractorInputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingMainInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingMainInteractorInputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - + func didReceiveFee(viewModel: LocalizableResource?) { + + return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) + + } - func setup() { + func didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.didReceiveRewardDestination(viewModel: viewModel)) } - func saveNetworkInfoViewExpansion(isExpanded: Bool) { + func didCompletionAccountSelection() { - return cuckoo_manager.call("saveNetworkInfoViewExpansion(isExpanded: Bool)", - parameters: (isExpanded), - escapingParameters: (isExpanded), + return cuckoo_manager.call("didCompletionAccountSelection()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.saveNetworkInfoViewExpansion(isExpanded: isExpanded)) + defaultCall: __defaultImplStub!.didCompletionAccountSelection()) } - func save(chainAsset: ChainAsset) { + public func applyLocalization() { - return cuckoo_manager.call("save(chainAsset: ChainAsset)", - parameters: (chainAsset), - escapingParameters: (chainAsset), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.save(chainAsset: chainAsset)) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_StakingMainInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDestSetupViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -42955,24 +42635,44 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func saveNetworkInfoViewExpansion(isExpanded: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorInputProtocol.self, method: "saveNetworkInfoViewExpansion(isExpanded: Bool)", parameterMatchers: matchers)) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func save(chainAsset: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainAsset)> where M1.MatchedType == ChainAsset { - let matchers: [Cuckoo.ParameterMatcher<(ChainAsset)>] = [wrap(matchable: chainAsset) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorInputProtocol.self, method: "save(chainAsset: ChainAsset)", parameterMatchers: matchers)) + + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") + } + + + func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + } + + func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChangeRewardDestinationViewModel?)> where M1.OptionalMatchedType == ChangeRewardDestinationViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ChangeRewardDestinationViewModel?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupViewProtocol.self, method: "didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?)", parameterMatchers: matchers)) + } + + func didCompletionAccountSelection() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupViewProtocol.self, method: "didCompletionAccountSelection()", parameterMatchers: matchers)) + } + + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingMainInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDestSetupViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -42984,30 +42684,80 @@ import SoraFoundation } + + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func saveNetworkInfoViewExpansion(isExpanded: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] - return cuckoo_manager.verify("saveNetworkInfoViewExpansion(isExpanded: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.__DoNotUse<(ChangeRewardDestinationViewModel?), Void> where M1.OptionalMatchedType == ChangeRewardDestinationViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ChangeRewardDestinationViewModel?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func save(chainAsset: M1) -> Cuckoo.__DoNotUse<(ChainAsset), Void> where M1.MatchedType == ChainAsset { - let matchers: [Cuckoo.ParameterMatcher<(ChainAsset)>] = [wrap(matchable: chainAsset) { $0 }] - return cuckoo_manager.verify("save(chainAsset: ChainAsset)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didCompletionAccountSelection() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didCompletionAccountSelection()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingMainInteractorInputProtocolStub: StakingMainInteractorInputProtocol { + class StakingRewardDestSetupViewProtocolStub: StakingRewardDestSetupViewProtocol { + + + + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + + + + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + + } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } @@ -43015,19 +42765,25 @@ import SoraFoundation - func setup() { + func didReceiveFee(viewModel: LocalizableResource?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func saveNetworkInfoViewExpansion(isExpanded: Bool) { + func didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func save(chainAsset: ChainAsset) { + func didCompletionAccountSelection() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -43035,19 +42791,19 @@ import SoraFoundation - class MockStakingMainInteractorOutputProtocol: StakingMainInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardDestSetupPresenterProtocol: StakingRewardDestSetupPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingMainInteractorOutputProtocol + typealias MocksType = StakingRewardDestSetupPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingMainInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingMainInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDestSetupPresenterProtocol + typealias Verification = __VerificationProxy_StakingRewardDestSetupPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingMainInteractorOutputProtocol? + private var __defaultImplStub: StakingRewardDestSetupPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingMainInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardDestSetupPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -43060,81 +42816,96 @@ import SoraFoundation - func didReceiveAccountInfo(_ accountInfo: AccountInfo?) { + func setup() { - return cuckoo_manager.call("didReceiveAccountInfo(_: AccountInfo?)", - parameters: (accountInfo), - escapingParameters: (accountInfo), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(accountInfo)) + defaultCall: __defaultImplStub!.setup()) } - func didReceiveSelectedAccount(_ metaAccount: MetaAccountModel) { + func selectRestakeDestination() { - return cuckoo_manager.call("didReceiveSelectedAccount(_: MetaAccountModel)", - parameters: (metaAccount), - escapingParameters: (metaAccount), + return cuckoo_manager.call("selectRestakeDestination()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveSelectedAccount(metaAccount)) + defaultCall: __defaultImplStub!.selectRestakeDestination()) } - func didReceiveStakingSettings(_ stakingSettings: StakingAssetSettings) { + func selectPayoutDestination() { - return cuckoo_manager.call("didReceiveStakingSettings(_: StakingAssetSettings)", - parameters: (stakingSettings), - escapingParameters: (stakingSettings), + return cuckoo_manager.call("selectPayoutDestination()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStakingSettings(stakingSettings)) + defaultCall: __defaultImplStub!.selectPayoutDestination()) } - func didReceiveExpansion(_ isExpanded: Bool) { + func selectPayoutAccount() { - return cuckoo_manager.call("didReceiveExpansion(_: Bool)", - parameters: (isExpanded), - escapingParameters: (isExpanded), + return cuckoo_manager.call("selectPayoutAccount()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveExpansion(isExpanded)) + defaultCall: __defaultImplStub!.selectPayoutAccount()) } - func didReceiveError(_ error: Error) { + func displayLearnMore() { - return cuckoo_manager.call("didReceiveError(_: Error)", - parameters: (error), - escapingParameters: (error), + return cuckoo_manager.call("displayLearnMore()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveError(error)) + defaultCall: __defaultImplStub!.displayLearnMore()) + + } + + + + func proceed() { + + return cuckoo_manager.call("proceed()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.proceed()) } - struct __StubbingProxy_StakingMainInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDestSetupPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -43142,34 +42913,39 @@ import SoraFoundation } - func didReceiveAccountInfo(_ accountInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountInfo?)> where M1.OptionalMatchedType == AccountInfo { - let matchers: [Cuckoo.ParameterMatcher<(AccountInfo?)>] = [wrap(matchable: accountInfo) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveAccountInfo(_: AccountInfo?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func didReceiveSelectedAccount(_ metaAccount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(MetaAccountModel)> where M1.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: metaAccount) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveSelectedAccount(_: MetaAccountModel)", parameterMatchers: matchers)) + func selectRestakeDestination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "selectRestakeDestination()", parameterMatchers: matchers)) } - func didReceiveStakingSettings(_ stakingSettings: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingAssetSettings)> where M1.MatchedType == StakingAssetSettings { - let matchers: [Cuckoo.ParameterMatcher<(StakingAssetSettings)>] = [wrap(matchable: stakingSettings) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveStakingSettings(_: StakingAssetSettings)", parameterMatchers: matchers)) + func selectPayoutDestination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "selectPayoutDestination()", parameterMatchers: matchers)) } - func didReceiveExpansion(_ isExpanded: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveExpansion(_: Bool)", parameterMatchers: matchers)) + func selectPayoutAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "selectPayoutAccount()", parameterMatchers: matchers)) } - func didReceiveError(_ error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainInteractorOutputProtocol.self, method: "didReceiveError(_: Error)", parameterMatchers: matchers)) + func displayLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "displayLearnMore()", parameterMatchers: matchers)) + } + + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingMainInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDestSetupPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -43184,39 +42960,45 @@ import SoraFoundation @discardableResult - func didReceiveAccountInfo(_ accountInfo: M1) -> Cuckoo.__DoNotUse<(AccountInfo?), Void> where M1.OptionalMatchedType == AccountInfo { - let matchers: [Cuckoo.ParameterMatcher<(AccountInfo?)>] = [wrap(matchable: accountInfo) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(_: AccountInfo?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveSelectedAccount(_ metaAccount: M1) -> Cuckoo.__DoNotUse<(MetaAccountModel), Void> where M1.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(MetaAccountModel)>] = [wrap(matchable: metaAccount) { $0 }] - return cuckoo_manager.verify("didReceiveSelectedAccount(_: MetaAccountModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectRestakeDestination() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectRestakeDestination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStakingSettings(_ stakingSettings: M1) -> Cuckoo.__DoNotUse<(StakingAssetSettings), Void> where M1.MatchedType == StakingAssetSettings { - let matchers: [Cuckoo.ParameterMatcher<(StakingAssetSettings)>] = [wrap(matchable: stakingSettings) { $0 }] - return cuckoo_manager.verify("didReceiveStakingSettings(_: StakingAssetSettings)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectPayoutDestination() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectPayoutDestination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveExpansion(_ isExpanded: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: isExpanded) { $0 }] - return cuckoo_manager.verify("didReceiveExpansion(_: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectPayoutAccount() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectPayoutAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveError(_ error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return cuckoo_manager.verify("didReceiveError(_: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func displayLearnMore() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("displayLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func proceed() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingMainInteractorOutputProtocolStub: StakingMainInteractorOutputProtocol { + class StakingRewardDestSetupPresenterProtocolStub: StakingRewardDestSetupPresenterProtocol { @@ -43224,31 +43006,37 @@ import SoraFoundation - func didReceiveAccountInfo(_ accountInfo: AccountInfo?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveSelectedAccount(_ metaAccount: MetaAccountModel) { + func selectRestakeDestination() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStakingSettings(_ stakingSettings: StakingAssetSettings) { + func selectPayoutDestination() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveExpansion(_ isExpanded: Bool) { + func selectPayoutAccount() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveError(_ error: Error) { + func displayLearnMore() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func proceed() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -43256,19 +43044,19 @@ import SoraFoundation - class MockStakingMainWireframeProtocol: StakingMainWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardDestSetupInteractorInputProtocol: StakingRewardDestSetupInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingMainWireframeProtocol + typealias MocksType = StakingRewardDestSetupInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingMainWireframeProtocol - typealias Verification = __VerificationProxy_StakingMainWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDestSetupInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingRewardDestSetupInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingMainWireframeProtocol? + private var __defaultImplStub: StakingRewardDestSetupInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingMainWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardDestSetupInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -43281,66 +43069,51 @@ import SoraFoundation - func showChainAssetSelection(from view: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate) { - - return cuckoo_manager.call("showChainAssetSelection(from: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate)", - parameters: (view, selectedChainAssetId, delegate), - escapingParameters: (view, selectedChainAssetId, delegate), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.showChainAssetSelection(from: view, selectedChainAssetId: selectedChainAssetId, delegate: delegate)) - - } - - - - func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) { + func setup() { - return cuckoo_manager.call("showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", - parameters: (view, wallet), - escapingParameters: (view, wallet), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showWalletDetails(from: view, wallet: wallet)) + defaultCall: __defaultImplStub!.setup()) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func estimateFee() { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("estimateFee()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.estimateFee()) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func fetchPayoutAccounts() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("fetchPayoutAccounts()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.fetchPayoutAccounts()) } - struct __StubbingProxy_StakingMainWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDestSetupInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -43348,29 +43121,24 @@ import SoraFoundation } - func showChainAssetSelection(from view: M1, selectedChainAssetId: M2, delegate: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingMainViewProtocol?, ChainAssetId?, AssetSelectionDelegate)> where M1.OptionalMatchedType == StakingMainViewProtocol, M2.OptionalMatchedType == ChainAssetId, M3.MatchedType == AssetSelectionDelegate { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?, ChainAssetId?, AssetSelectionDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: selectedChainAssetId) { $0.1 }, wrap(matchable: delegate) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainWireframeProtocol.self, method: "showChainAssetSelection(from: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate)", parameterMatchers: matchers)) - } - - func showWalletDetails(from view: M1, wallet: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, MetaAccountModel)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaAccountModel)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: wallet) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainWireframeProtocol.self, method: "showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func fetchPayoutAccounts() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorInputProtocol.self, method: "fetchPayoutAccounts()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingMainWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDestSetupInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -43385,33 +43153,27 @@ import SoraFoundation @discardableResult - func showChainAssetSelection(from view: M1, selectedChainAssetId: M2, delegate: M3) -> Cuckoo.__DoNotUse<(StakingMainViewProtocol?, ChainAssetId?, AssetSelectionDelegate), Void> where M1.OptionalMatchedType == StakingMainViewProtocol, M2.OptionalMatchedType == ChainAssetId, M3.MatchedType == AssetSelectionDelegate { - let matchers: [Cuckoo.ParameterMatcher<(StakingMainViewProtocol?, ChainAssetId?, AssetSelectionDelegate)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: selectedChainAssetId) { $0.1 }, wrap(matchable: delegate) { $0.2 }] - return cuckoo_manager.verify("showChainAssetSelection(from: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showWalletDetails(from view: M1, wallet: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, MetaAccountModel), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaAccountModel { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaAccountModel)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: wallet) { $0.1 }] - return cuckoo_manager.verify("showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func fetchPayoutAccounts() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("fetchPayoutAccounts()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingMainWireframeProtocolStub: StakingMainWireframeProtocol { + class StakingRewardDestSetupInteractorInputProtocolStub: StakingRewardDestSetupInteractorInputProtocol { @@ -43419,25 +43181,19 @@ import SoraFoundation - func showChainAssetSelection(from view: StakingMainViewProtocol?, selectedChainAssetId: ChainAssetId?, delegate: AssetSelectionDelegate) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func estimateFee() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func fetchPayoutAccounts() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -43445,19 +43201,19 @@ import SoraFoundation - class MockStakingMainChildPresenterProtocol: StakingMainChildPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardDestSetupInteractorOutputProtocol: StakingRewardDestSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingMainChildPresenterProtocol + typealias MocksType = StakingRewardDestSetupInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingMainChildPresenterProtocol - typealias Verification = __VerificationProxy_StakingMainChildPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDestSetupInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingRewardDestSetupInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingMainChildPresenterProtocol? + private var __defaultImplStub: StakingRewardDestSetupInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingMainChildPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardDestSetupInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -43470,156 +43226,186 @@ import SoraFoundation - func setup() { + func didReceiveFee(result: Result) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - func performMainAction() { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("performMainAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performMainAction()) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - func performRewardInfoAction() { + func didReceiveStashItem(result: Result) { - return cuckoo_manager.call("performRewardInfoAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveStashItem(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performRewardInfoAction()) + defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) } - func performChangeValidatorsAction() { + func didReceiveController(result: Result) { - return cuckoo_manager.call("performChangeValidatorsAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveController(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performChangeValidatorsAction()) + defaultCall: __defaultImplStub!.didReceiveController(result: result)) } - func performSetupValidatorsForBondedAction() { + func didReceiveStash(result: Result) { - return cuckoo_manager.call("performSetupValidatorsForBondedAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveStash(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performSetupValidatorsForBondedAction()) + defaultCall: __defaultImplStub!.didReceiveStash(result: result)) } - func performStakeMoreAction() { + func didReceiveStakingLedger(result: Result) { - return cuckoo_manager.call("performStakeMoreAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performStakeMoreAction()) + defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) } - func performRedeemAction() { + func didReceiveRewardDestinationAccount(result: Result?, Error>) { - return cuckoo_manager.call("performRedeemAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveRewardDestinationAccount(result: Result?, Error>)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performRedeemAction()) + defaultCall: __defaultImplStub!.didReceiveRewardDestinationAccount(result: result)) } - func performRebondAction() { + func didReceiveRewardDestinationAddress(result: Result?, Error>) { - return cuckoo_manager.call("performRebondAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveRewardDestinationAddress(result: Result?, Error>)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performRebondAction()) + defaultCall: __defaultImplStub!.didReceiveRewardDestinationAddress(result: result)) } - func performAnalyticsAction() { + func didReceiveCalculator(result: Result) { - return cuckoo_manager.call("performAnalyticsAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveCalculator(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performAnalyticsAction()) + defaultCall: __defaultImplStub!.didReceiveCalculator(result: result)) } - func performManageAction(_ action: StakingManageOption) { + func didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>) { - return cuckoo_manager.call("performManageAction(_: StakingManageOption)", - parameters: (action), - escapingParameters: (action), + return cuckoo_manager.call("didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.performManageAction(action)) + defaultCall: __defaultImplStub!.didReceiveAccounts(result: result)) + + } + + + + func didReceiveNomination(result: Result) { + + return cuckoo_manager.call("didReceiveNomination(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveNomination(result: result)) + + } + + + + func didReceiveAccountInfo(result: Result) { + + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - struct __StubbingProxy_StakingMainChildPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDestSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -43627,59 +43413,69 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } - func performMainAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performMainAction()", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) } - func performRewardInfoAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performRewardInfoAction()", parameterMatchers: matchers)) + func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) } - func performChangeValidatorsAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performChangeValidatorsAction()", parameterMatchers: matchers)) + func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) } - func performSetupValidatorsForBondedAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performSetupValidatorsForBondedAction()", parameterMatchers: matchers)) + func didReceiveStash(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveStash(result: Result)", parameterMatchers: matchers)) } - func performStakeMoreAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performStakeMoreAction()", parameterMatchers: matchers)) + func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) } - func performRedeemAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performRedeemAction()", parameterMatchers: matchers)) + func didReceiveRewardDestinationAccount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result?, Error>)> where M1.MatchedType == Result?, Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result?, Error>)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveRewardDestinationAccount(result: Result?, Error>)", parameterMatchers: matchers)) } - func performRebondAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performRebondAction()", parameterMatchers: matchers)) + func didReceiveRewardDestinationAddress(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result?, Error>)> where M1.MatchedType == Result?, Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result?, Error>)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveRewardDestinationAddress(result: Result?, Error>)", parameterMatchers: matchers)) } - func performAnalyticsAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performAnalyticsAction()", parameterMatchers: matchers)) + func didReceiveCalculator(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveCalculator(result: Result)", parameterMatchers: matchers)) } - func performManageAction(_ action: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingManageOption)> where M1.MatchedType == StakingManageOption { - let matchers: [Cuckoo.ParameterMatcher<(StakingManageOption)>] = [wrap(matchable: action) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingMainChildPresenterProtocol.self, method: "performManageAction(_: StakingManageOption)", parameterMatchers: matchers)) + func didReceiveAccounts(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[MetaChainAccountResponse], Error>)> where M1.MatchedType == Result<[MetaChainAccountResponse], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[MetaChainAccountResponse], Error>)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", parameterMatchers: matchers)) + } + + func didReceiveNomination(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveNomination(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingMainChildPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDestSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -43694,69 +43490,81 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performMainAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performMainAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performRewardInfoAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performRewardInfoAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performChangeValidatorsAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performChangeValidatorsAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performSetupValidatorsForBondedAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performSetupValidatorsForBondedAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStash(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStash(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performStakeMoreAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performStakeMoreAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performRedeemAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performRedeemAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveRewardDestinationAccount(result: M1) -> Cuckoo.__DoNotUse<(Result?, Error>), Void> where M1.MatchedType == Result?, Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result?, Error>)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveRewardDestinationAccount(result: Result?, Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performRebondAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performRebondAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveRewardDestinationAddress(result: M1) -> Cuckoo.__DoNotUse<(Result?, Error>), Void> where M1.MatchedType == Result?, Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result?, Error>)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveRewardDestinationAddress(result: Result?, Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performAnalyticsAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("performAnalyticsAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveCalculator(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveCalculator(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func performManageAction(_ action: M1) -> Cuckoo.__DoNotUse<(StakingManageOption), Void> where M1.MatchedType == StakingManageOption { - let matchers: [Cuckoo.ParameterMatcher<(StakingManageOption)>] = [wrap(matchable: action) { $0 }] - return cuckoo_manager.verify("performManageAction(_: StakingManageOption)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccounts(result: M1) -> Cuckoo.__DoNotUse<(Result<[MetaChainAccountResponse], Error>), Void> where M1.MatchedType == Result<[MetaChainAccountResponse], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[MetaChainAccountResponse], Error>)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveNomination(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveNomination(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingMainChildPresenterProtocolStub: StakingMainChildPresenterProtocol { + class StakingRewardDestSetupInteractorOutputProtocolStub: StakingRewardDestSetupInteractorOutputProtocol { @@ -43764,268 +43572,180 @@ import SoraFoundation - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func performMainAction() { + func didReceiveFee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performRewardInfoAction() { + func didReceivePriceData(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performChangeValidatorsAction() { + func didReceiveStashItem(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performSetupValidatorsForBondedAction() { + func didReceiveController(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performStakeMoreAction() { + func didReceiveStash(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performRedeemAction() { + func didReceiveStakingLedger(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performRebondAction() { + func didReceiveRewardDestinationAccount(result: Result?, Error>) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performAnalyticsAction() { + func didReceiveRewardDestinationAddress(result: Result?, Error>) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func performManageAction(_ action: StakingManageOption) { + func didReceiveCalculator(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - -import Cuckoo -@testable import novawallet - -import SoraFoundation - - - class MockStakingPayoutConfirmationViewProtocol: StakingPayoutConfirmationViewProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingPayoutConfirmationViewProtocol - - typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationViewProtocol - typealias Verification = __VerificationProxy_StakingPayoutConfirmationViewProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: StakingPayoutConfirmationViewProtocol? - - func enableDefaultImplementation(_ stub: StakingPayoutConfirmationViewProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } - - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } - - } - - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } - + func didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } - + func didReceiveNomination(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - + + func didReceiveAccountInfo(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + + class MockStakingRewardDestSetupWireframeProtocol: StakingRewardDestSetupWireframeProtocol, Cuckoo.ProtocolMock { + typealias MocksType = StakingRewardDestSetupWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDestSetupWireframeProtocol + typealias Verification = __VerificationProxy_StakingRewardDestSetupWireframeProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func didRecieve(viewModel: LocalizableResource) { - - return cuckoo_manager.call("didRecieve(viewModel: LocalizableResource)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didRecieve(viewModel: viewModel)) - + private var __defaultImplStub: StakingRewardDestSetupWireframeProtocol? + + func enableDefaultImplementation(_ stub: StakingRewardDestSetupWireframeProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func didRecieve(amountViewModel: LocalizableResource) { + + + + + func proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination) { - return cuckoo_manager.call("didRecieve(amountViewModel: LocalizableResource)", - parameters: (amountViewModel), - escapingParameters: (amountViewModel), + return cuckoo_manager.call("proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination)", + parameters: (view, rewardDestination), + escapingParameters: (view, rewardDestination), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didRecieve(amountViewModel: amountViewModel)) + defaultCall: __defaultImplStub!.proceed(view: view, rewardDestination: rewardDestination)) } - func didReceive(feeViewModel: LocalizableResource?) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - return cuckoo_manager.call("didReceive(feeViewModel: LocalizableResource?)", - parameters: (feeViewModel), - escapingParameters: (feeViewModel), + return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", + parameters: (url, view, style), + escapingParameters: (url, view, style), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(feeViewModel: feeViewModel)) + defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) } - public func applyLocalization() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - func didStartLoading() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("didStartLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStartLoading()) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - func didStopLoading() { + func presentAccountSelection(_ accounts: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from view: ControllerBackedProtocol?, context: AnyObject?) { - return cuckoo_manager.call("didStopLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", + parameters: (accounts, selectedAccountItem, title, delegate, view, context), + escapingParameters: (accounts, selectedAccountItem, title, delegate, view, context), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopLoading()) + defaultCall: __defaultImplStub!.presentAccountSelection(accounts, selectedAccountItem: selectedAccountItem, title: title, delegate: delegate, from: view, context: context)) } - struct __StubbingProxy_StakingPayoutConfirmationViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDestSetupWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -44033,64 +43753,34 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") - } - - - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") - } - - - func didRecieve(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didRecieve(viewModel: LocalizableResource)", parameterMatchers: matchers)) - } - - func didRecieve(amountViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: amountViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didRecieve(amountViewModel: LocalizableResource)", parameterMatchers: matchers)) + func proceed(view: M1, rewardDestination: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRewardDestSetupViewProtocol?, RewardDestination)> where M1.OptionalMatchedType == StakingRewardDestSetupViewProtocol, M2.MatchedType == RewardDestination { + let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestSetupViewProtocol?, RewardDestination)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: rewardDestination) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination)", parameterMatchers: matchers)) } - func didReceive(feeViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: feeViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didReceive(feeViewModel: LocalizableResource?)", parameterMatchers: matchers)) + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + func presentAccountSelection(_ accounts: M1, selectedAccountItem: M2, title: M3, delegate: M4, from view: M5, context: M6) -> Cuckoo.ProtocolStubNoReturnFunction<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)> where M1.MatchedType == [MetaChainAccountResponse], M2.OptionalMatchedType == MetaChainAccountResponse, M3.MatchedType == LocalizableResource, M4.MatchedType == ModalPickerViewControllerDelegate, M5.OptionalMatchedType == ControllerBackedProtocol, M6.OptionalMatchedType == AnyObject { + let matchers: [Cuckoo.ParameterMatcher<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)>] = [wrap(matchable: accounts) { $0.0 }, wrap(matchable: selectedAccountItem) { $0.1 }, wrap(matchable: title) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: view) { $0.4 }, wrap(matchable: context) { $0.5 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingPayoutConfirmationViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDestSetupWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -44102,120 +43792,42 @@ import SoraFoundation } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didRecieve(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didRecieve(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didRecieve(amountViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: amountViewModel) { $0 }] - return cuckoo_manager.verify("didRecieve(amountViewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceed(view: M1, rewardDestination: M2) -> Cuckoo.__DoNotUse<(StakingRewardDestSetupViewProtocol?, RewardDestination), Void> where M1.OptionalMatchedType == StakingRewardDestSetupViewProtocol, M2.MatchedType == RewardDestination { + let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestSetupViewProtocol?, RewardDestination)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: rewardDestination) { $0.1 }] + return cuckoo_manager.verify("proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(feeViewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: feeViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(feeViewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentAccountSelection(_ accounts: M1, selectedAccountItem: M2, title: M3, delegate: M4, from view: M5, context: M6) -> Cuckoo.__DoNotUse<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?), Void> where M1.MatchedType == [MetaChainAccountResponse], M2.OptionalMatchedType == MetaChainAccountResponse, M3.MatchedType == LocalizableResource, M4.MatchedType == ModalPickerViewControllerDelegate, M5.OptionalMatchedType == ControllerBackedProtocol, M6.OptionalMatchedType == AnyObject { + let matchers: [Cuckoo.ParameterMatcher<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)>] = [wrap(matchable: accounts) { $0.0 }, wrap(matchable: selectedAccountItem) { $0.1 }, wrap(matchable: title) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: view) { $0.4 }, wrap(matchable: context) { $0.5 }] + return cuckoo_manager.verify("presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingPayoutConfirmationViewProtocolStub: StakingPayoutConfirmationViewProtocol { - - - - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - - - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - - } - - - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } + class StakingRewardDestSetupWireframeProtocolStub: StakingRewardDestSetupWireframeProtocol { @@ -44223,114 +43835,156 @@ import SoraFoundation - func didRecieve(viewModel: LocalizableResource) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didRecieve(amountViewModel: LocalizableResource) { + func proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(feeViewModel: LocalizableResource?) { + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoading() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStopLoading() { + func presentAccountSelection(_ accounts: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from view: ControllerBackedProtocol?, context: AnyObject?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet + +import SoraFoundation + - class MockStakingPayoutConfirmationPresenterProtocol: StakingPayoutConfirmationPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardDetailsViewProtocol: StakingRewardDetailsViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingPayoutConfirmationPresenterProtocol + typealias MocksType = StakingRewardDetailsViewProtocol - typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationPresenterProtocol - typealias Verification = __VerificationProxy_StakingPayoutConfirmationPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDetailsViewProtocol + typealias Verification = __VerificationProxy_StakingRewardDetailsViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingPayoutConfirmationPresenterProtocol? + private var __defaultImplStub: StakingRewardDetailsViewProtocol? - func enableDefaultImplementation(_ stub: StakingPayoutConfirmationPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardDetailsViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } + + + + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } + + } + - func setup() { + func didReceive(amountViewModel: BalanceViewModelProtocol) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(amountViewModel: BalanceViewModelProtocol)", + parameters: (amountViewModel), + escapingParameters: (amountViewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.didReceive(amountViewModel: amountViewModel)) } - func proceed() { + func didReceive(validatorViewModel: StackCellViewModel) { - return cuckoo_manager.call("proceed()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(validatorViewModel: StackCellViewModel)", + parameters: (validatorViewModel), + escapingParameters: (validatorViewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.didReceive(validatorViewModel: validatorViewModel)) } - func presentAccountOptions() { + func didReceive(eraViewModel: StackCellViewModel) { - return cuckoo_manager.call("presentAccountOptions()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceive(eraViewModel: StackCellViewModel)", + parameters: (eraViewModel), + escapingParameters: (eraViewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentAccountOptions()) + defaultCall: __defaultImplStub!.didReceive(eraViewModel: eraViewModel)) + + } + + + + func didReceive(remainedTime: NSAttributedString) { + + return cuckoo_manager.call("didReceive(remainedTime: NSAttributedString)", + parameters: (remainedTime), + escapingParameters: (remainedTime), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceive(remainedTime: remainedTime)) } - struct __StubbingProxy_StakingPayoutConfirmationPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDetailsViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -44338,24 +43992,39 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func presentAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationPresenterProtocol.self, method: "presentAccountOptions()", parameterMatchers: matchers)) + + func didReceive(amountViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BalanceViewModelProtocol)> where M1.MatchedType == BalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol)>] = [wrap(matchable: amountViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsViewProtocol.self, method: "didReceive(amountViewModel: BalanceViewModelProtocol)", parameterMatchers: matchers)) + } + + func didReceive(validatorViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StackCellViewModel)> where M1.MatchedType == StackCellViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StackCellViewModel)>] = [wrap(matchable: validatorViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsViewProtocol.self, method: "didReceive(validatorViewModel: StackCellViewModel)", parameterMatchers: matchers)) + } + + func didReceive(eraViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StackCellViewModel)> where M1.MatchedType == StackCellViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StackCellViewModel)>] = [wrap(matchable: eraViewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsViewProtocol.self, method: "didReceive(eraViewModel: StackCellViewModel)", parameterMatchers: matchers)) + } + + func didReceive(remainedTime: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(NSAttributedString)> where M1.MatchedType == NSAttributedString { + let matchers: [Cuckoo.ParameterMatcher<(NSAttributedString)>] = [wrap(matchable: remainedTime) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsViewProtocol.self, method: "didReceive(remainedTime: NSAttributedString)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingPayoutConfirmationPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDetailsViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -44367,30 +44036,64 @@ import SoraFoundation } + + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(amountViewModel: M1) -> Cuckoo.__DoNotUse<(BalanceViewModelProtocol), Void> where M1.MatchedType == BalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol)>] = [wrap(matchable: amountViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(amountViewModel: BalanceViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(validatorViewModel: M1) -> Cuckoo.__DoNotUse<(StackCellViewModel), Void> where M1.MatchedType == StackCellViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StackCellViewModel)>] = [wrap(matchable: validatorViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(validatorViewModel: StackCellViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(eraViewModel: M1) -> Cuckoo.__DoNotUse<(StackCellViewModel), Void> where M1.MatchedType == StackCellViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StackCellViewModel)>] = [wrap(matchable: eraViewModel) { $0 }] + return cuckoo_manager.verify("didReceive(eraViewModel: StackCellViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(remainedTime: M1) -> Cuckoo.__DoNotUse<(NSAttributedString), Void> where M1.MatchedType == NSAttributedString { + let matchers: [Cuckoo.ParameterMatcher<(NSAttributedString)>] = [wrap(matchable: remainedTime) { $0 }] + return cuckoo_manager.verify("didReceive(remainedTime: NSAttributedString)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingPayoutConfirmationPresenterProtocolStub: StakingPayoutConfirmationPresenterProtocol { + class StakingRewardDetailsViewProtocolStub: StakingRewardDetailsViewProtocol { + + + + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + + + + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + + } @@ -44398,19 +44101,25 @@ import SoraFoundation - func setup() { + func didReceive(amountViewModel: BalanceViewModelProtocol) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func proceed() { + func didReceive(validatorViewModel: StackCellViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentAccountOptions() { + func didReceive(eraViewModel: StackCellViewModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceive(remainedTime: NSAttributedString) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -44418,19 +44127,19 @@ import SoraFoundation - class MockStakingPayoutConfirmationInteractorInputProtocol: StakingPayoutConfirmationInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardDetailsPresenterProtocol: StakingRewardDetailsPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingPayoutConfirmationInteractorInputProtocol + typealias MocksType = StakingRewardDetailsPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingPayoutConfirmationInteractorInputProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDetailsPresenterProtocol + typealias Verification = __VerificationProxy_StakingRewardDetailsPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingPayoutConfirmationInteractorInputProtocol? + private var __defaultImplStub: StakingRewardDetailsPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingPayoutConfirmationInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardDetailsPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -44458,36 +44167,36 @@ import SoraFoundation - func submitPayout() { + func handlePayoutAction() { - return cuckoo_manager.call("submitPayout()", + return cuckoo_manager.call("handlePayoutAction()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.submitPayout()) + defaultCall: __defaultImplStub!.handlePayoutAction()) } - func estimateFee() { + func handleValidatorAccountAction() { - return cuckoo_manager.call("estimateFee()", + return cuckoo_manager.call("handleValidatorAccountAction()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFee()) + defaultCall: __defaultImplStub!.handleValidatorAccountAction()) } - struct __StubbingProxy_StakingPayoutConfirmationInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDetailsPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -44497,22 +44206,22 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func submitPayout() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func handlePayoutAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorInputProtocol.self, method: "submitPayout()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsPresenterProtocol.self, method: "handlePayoutAction()", parameterMatchers: matchers)) } - func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func handleValidatorAccountAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsPresenterProtocol.self, method: "handleValidatorAccountAction()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingPayoutConfirmationInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDetailsPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -44533,21 +44242,21 @@ import SoraFoundation } @discardableResult - func submitPayout() -> Cuckoo.__DoNotUse<(), Void> { + func handlePayoutAction() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("submitPayout()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("handlePayoutAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { + func handleValidatorAccountAction() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("handleValidatorAccountAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingPayoutConfirmationInteractorInputProtocolStub: StakingPayoutConfirmationInteractorInputProtocol { + class StakingRewardDetailsPresenterProtocolStub: StakingRewardDetailsPresenterProtocol { @@ -44561,13 +44270,13 @@ import SoraFoundation - func submitPayout() { + func handlePayoutAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func estimateFee() { + func handleValidatorAccountAction() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -44575,19 +44284,19 @@ import SoraFoundation - class MockStakingPayoutConfirmationInteractorOutputProtocol: StakingPayoutConfirmationInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardDetailsInteractorInputProtocol: StakingRewardDetailsInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingPayoutConfirmationInteractorOutputProtocol + typealias MocksType = StakingRewardDetailsInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingPayoutConfirmationInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDetailsInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingRewardDetailsInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingPayoutConfirmationInteractorOutputProtocol? + private var __defaultImplStub: StakingRewardDetailsInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingPayoutConfirmationInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardDetailsInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -44600,111 +44309,114 @@ import SoraFoundation - func didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal) { + func setup() { - return cuckoo_manager.call("didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal)", - parameters: (account, rewardAmount), - escapingParameters: (account, rewardAmount), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didRecieve(account: account, rewardAmount: rewardAmount)) + defaultCall: __defaultImplStub!.setup()) } + + struct __StubbingProxy_StakingRewardDetailsInteractorInputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_StakingRewardDetailsInteractorInputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class StakingRewardDetailsInteractorInputProtocolStub: StakingRewardDetailsInteractorInputProtocol { + - func didReceivePriceData(result: Result) { - - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) - - } + - func didReceiveAccountInfo(result: Result) { - - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) - + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockStakingRewardDetailsInteractorOutputProtocol: StakingRewardDetailsInteractorOutputProtocol, Cuckoo.ProtocolMock { + typealias MocksType = StakingRewardDetailsInteractorOutputProtocol - func didReceiveFee(result: Result) { - - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) - - } - - + typealias Stubbing = __StubbingProxy_StakingRewardDetailsInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingRewardDetailsInteractorOutputProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func didStartPayout() { - - return cuckoo_manager.call("didStartPayout()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didStartPayout()) - + private var __defaultImplStub: StakingRewardDetailsInteractorOutputProtocol? + + func enableDefaultImplementation(_ stub: StakingRewardDetailsInteractorOutputProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func didCompletePayout(txHashes: [String]) { - - return cuckoo_manager.call("didCompletePayout(txHashes: [String])", - parameters: (txHashes), - escapingParameters: (txHashes), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didCompletePayout(txHashes: txHashes)) - - } + - func didFailPayout(error: Error) { + func didReceive(priceResult: Result) { - return cuckoo_manager.call("didFailPayout(error: Error)", - parameters: (error), - escapingParameters: (error), + return cuckoo_manager.call("didReceive(priceResult: Result)", + parameters: (priceResult), + escapingParameters: (priceResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didFailPayout(error: error)) + defaultCall: __defaultImplStub!.didReceive(priceResult: priceResult)) } - struct __StubbingProxy_StakingPayoutConfirmationInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDetailsInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -44712,44 +44424,14 @@ import SoraFoundation } - func didRecieve(account: M1, rewardAmount: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(MetaChainAccountResponse, Decimal)> where M1.MatchedType == MetaChainAccountResponse, M2.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(MetaChainAccountResponse, Decimal)>] = [wrap(matchable: account) { $0.0 }, wrap(matchable: rewardAmount) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal)", parameterMatchers: matchers)) - } - - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) - } - - func didStartPayout() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didStartPayout()", parameterMatchers: matchers)) - } - - func didCompletePayout(txHashes: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([String])> where M1.MatchedType == [String] { - let matchers: [Cuckoo.ParameterMatcher<([String])>] = [wrap(matchable: txHashes) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didCompletePayout(txHashes: [String])", parameterMatchers: matchers)) - } - - func didFailPayout(error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationInteractorOutputProtocol.self, method: "didFailPayout(error: Error)", parameterMatchers: matchers)) + func didReceive(priceResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsInteractorOutputProtocol.self, method: "didReceive(priceResult: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingPayoutConfirmationInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDetailsInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -44764,51 +44446,15 @@ import SoraFoundation @discardableResult - func didRecieve(account: M1, rewardAmount: M2) -> Cuckoo.__DoNotUse<(MetaChainAccountResponse, Decimal), Void> where M1.MatchedType == MetaChainAccountResponse, M2.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(MetaChainAccountResponse, Decimal)>] = [wrap(matchable: account) { $0.0 }, wrap(matchable: rewardAmount) { $0.1 }] - return cuckoo_manager.verify("didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didStartPayout() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartPayout()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didCompletePayout(txHashes: M1) -> Cuckoo.__DoNotUse<([String]), Void> where M1.MatchedType == [String] { - let matchers: [Cuckoo.ParameterMatcher<([String])>] = [wrap(matchable: txHashes) { $0 }] - return cuckoo_manager.verify("didCompletePayout(txHashes: [String])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didFailPayout(error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { - let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] - return cuckoo_manager.verify("didFailPayout(error: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(priceResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] + return cuckoo_manager.verify("didReceive(priceResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingPayoutConfirmationInteractorOutputProtocolStub: StakingPayoutConfirmationInteractorOutputProtocol { + class StakingRewardDetailsInteractorOutputProtocolStub: StakingRewardDetailsInteractorOutputProtocol { @@ -44816,43 +44462,7 @@ import SoraFoundation - func didRecieve(account: MetaChainAccountResponse, rewardAmount: Decimal) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceivePriceData(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAccountInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didStartPayout() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didCompletePayout(txHashes: [String]) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didFailPayout(error: Error) { + func didReceive(priceResult: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -44860,19 +44470,19 @@ import SoraFoundation - class MockStakingPayoutConfirmationWireframeProtocol: StakingPayoutConfirmationWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardDetailsWireframeProtocol: StakingRewardDetailsWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingPayoutConfirmationWireframeProtocol + typealias MocksType = StakingRewardDetailsWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingPayoutConfirmationWireframeProtocol - typealias Verification = __VerificationProxy_StakingPayoutConfirmationWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingRewardDetailsWireframeProtocol + typealias Verification = __VerificationProxy_StakingRewardDetailsWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingPayoutConfirmationWireframeProtocol? + private var __defaultImplStub: StakingRewardDetailsWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingPayoutConfirmationWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardDetailsWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -44885,51 +44495,21 @@ import SoraFoundation - func complete(from view: StakingPayoutConfirmationViewProtocol?) { - - return cuckoo_manager.call("complete(from: StakingPayoutConfirmationViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.complete(from: view)) - - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) - - } - - - - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func showPayoutConfirmation(from view: ControllerBackedProtocol?, payoutInfo: PayoutInfo) { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("showPayoutConfirmation(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo)", + parameters: (view, payoutInfo), + escapingParameters: (view, payoutInfo), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.showPayoutConfirmation(from: view, payoutInfo: payoutInfo)) } - struct __StubbingProxy_StakingPayoutConfirmationWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardDetailsWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -44937,24 +44517,14 @@ import SoraFoundation } - func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingPayoutConfirmationViewProtocol?)> where M1.OptionalMatchedType == StakingPayoutConfirmationViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingPayoutConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationWireframeProtocol.self, method: "complete(from: StakingPayoutConfirmationViewProtocol?)", parameterMatchers: matchers)) - } - - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutConfirmationWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func showPayoutConfirmation(from view: M1, payoutInfo: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, PayoutInfo)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == PayoutInfo { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, PayoutInfo)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: payoutInfo) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsWireframeProtocol.self, method: "showPayoutConfirmation(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingPayoutConfirmationWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardDetailsWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -44969,27 +44539,15 @@ import SoraFoundation @discardableResult - func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingPayoutConfirmationViewProtocol?), Void> where M1.OptionalMatchedType == StakingPayoutConfirmationViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingPayoutConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("complete(from: StakingPayoutConfirmationViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showPayoutConfirmation(from view: M1, payoutInfo: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, PayoutInfo), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == PayoutInfo { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, PayoutInfo)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: payoutInfo) { $0.1 }] + return cuckoo_manager.verify("showPayoutConfirmation(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingPayoutConfirmationWireframeProtocolStub: StakingPayoutConfirmationWireframeProtocol { + class StakingRewardDetailsWireframeProtocolStub: StakingRewardDetailsWireframeProtocol { @@ -44997,19 +44555,7 @@ import SoraFoundation - func complete(from view: StakingPayoutConfirmationViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func showPayoutConfirmation(from view: ControllerBackedProtocol?, payoutInfo: PayoutInfo) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -45019,24 +44565,23 @@ import SoraFoundation import Cuckoo @testable import novawallet -import BigInt -import Foundation import SoraFoundation +import SoraUI - class MockStakingRebondConfirmationViewProtocol: StakingRebondConfirmationViewProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardPayoutsViewProtocol: StakingRewardPayoutsViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRebondConfirmationViewProtocol + typealias MocksType = StakingRewardPayoutsViewProtocol - typealias Stubbing = __StubbingProxy_StakingRebondConfirmationViewProtocol - typealias Verification = __VerificationProxy_StakingRebondConfirmationViewProtocol + typealias Stubbing = __StubbingProxy_StakingRewardPayoutsViewProtocol + typealias Verification = __VerificationProxy_StakingRewardPayoutsViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRebondConfirmationViewProtocol? + private var __defaultImplStub: StakingRewardPayoutsViewProtocol? - func enableDefaultImplementation(_ stub: StakingRebondConfirmationViewProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardPayoutsViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -45090,135 +44635,47 @@ import SoraFoundation Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } - - } - - - - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } - - } - - - - - - - - func didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel) { - - return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) - - } - - - - func didReceiveAmount(viewModel: LocalizableResource) { - - return cuckoo_manager.call("didReceiveAmount(viewModel: LocalizableResource)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAmount(viewModel: viewModel)) - - } - - - - func didReceiveFee(viewModel: LocalizableResource?) { - - return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) + defaultCall: __defaultImplStub!.localizationManager = newValue) + } } + - - public func applyLocalization() { - - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.applyLocalization()) - - } + - func didStartLoading() { + func reload(with state: StakingRewardPayoutsViewState) { - return cuckoo_manager.call("didStartLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("reload(with: StakingRewardPayoutsViewState)", + parameters: (state), + escapingParameters: (state), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStartLoading()) + defaultCall: __defaultImplStub!.reload(with: state)) } - func didStopLoading() { + public func applyLocalization() { - return cuckoo_manager.call("didStopLoading()", + return cuckoo_manager.call("applyLocalization()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopLoading()) + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_StakingRebondConfirmationViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardPayoutsViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -45226,64 +44683,34 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") - } - - - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRebondConfirmationViewModel)> where M1.MatchedType == StakingRebondConfirmationViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingRebondConfirmationViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel)", parameterMatchers: matchers)) - } - - func didReceiveAmount(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didReceiveAmount(viewModel: LocalizableResource)", parameterMatchers: matchers)) - } - - func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + func reload(with state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRewardPayoutsViewState)> where M1.MatchedType == StakingRewardPayoutsViewState { + let matchers: [Cuckoo.ParameterMatcher<(StakingRewardPayoutsViewState)>] = [wrap(matchable: state) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsViewProtocol.self, method: "reload(with: StakingRewardPayoutsViewState)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) - } - - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) - } - - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRebondConfirmationViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardPayoutsViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -45310,34 +44737,12 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingRebondConfirmationViewModel), Void> where M1.MatchedType == StakingRebondConfirmationViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingRebondConfirmationViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAmount(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveAmount(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload(with state: M1) -> Cuckoo.__DoNotUse<(StakingRewardPayoutsViewState), Void> where M1.MatchedType == StakingRewardPayoutsViewState { + let matchers: [Cuckoo.ParameterMatcher<(StakingRewardPayoutsViewState)>] = [wrap(matchable: state) { $0 }] + return cuckoo_manager.verify("reload(with: StakingRewardPayoutsViewState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -45346,22 +44751,10 @@ import SoraFoundation return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } - class StakingRebondConfirmationViewProtocolStub: StakingRebondConfirmationViewProtocol { + class StakingRewardPayoutsViewProtocolStub: StakingRewardPayoutsViewProtocol { @@ -45391,24 +44784,6 @@ import SoraFoundation set { } } - - - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - - } - - - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } @@ -45416,19 +44791,7 @@ import SoraFoundation - func didReceiveConfirmation(viewModel: StakingRebondConfirmationViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAmount(viewModel: LocalizableResource) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(viewModel: LocalizableResource?) { + func reload(with state: StakingRewardPayoutsViewState) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -45438,35 +44801,23 @@ import SoraFoundation return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - func didStartLoading() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didStopLoading() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - } - class MockStakingRebondConfirmationPresenterProtocol: StakingRebondConfirmationPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardPayoutsPresenterProtocol: StakingRewardPayoutsPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRebondConfirmationPresenterProtocol + typealias MocksType = StakingRewardPayoutsPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingRebondConfirmationPresenterProtocol - typealias Verification = __VerificationProxy_StakingRebondConfirmationPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingRewardPayoutsPresenterProtocol + typealias Verification = __VerificationProxy_StakingRewardPayoutsPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRebondConfirmationPresenterProtocol? + private var __defaultImplStub: StakingRewardPayoutsPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingRebondConfirmationPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardPayoutsPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -45494,36 +44845,66 @@ import SoraFoundation - func confirm() { + func handleSelectedHistory(at index: Int) { - return cuckoo_manager.call("confirm()", + return cuckoo_manager.call("handleSelectedHistory(at: Int)", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.handleSelectedHistory(at: index)) + + } + + + + func handlePayoutAction() { + + return cuckoo_manager.call("handlePayoutAction()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.confirm()) + defaultCall: __defaultImplStub!.handlePayoutAction()) } - func selectAccount() { + func reload() { - return cuckoo_manager.call("selectAccount()", + return cuckoo_manager.call("reload()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectAccount()) + defaultCall: __defaultImplStub!.reload()) + + } + + + + func getTimeLeftString(at index: Int) -> LocalizableResource? { + + return cuckoo_manager.call("getTimeLeftString(at: Int) -> LocalizableResource?", + parameters: (index), + escapingParameters: (index), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.getTimeLeftString(at: index)) } - struct __StubbingProxy_StakingRebondConfirmationPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardPayoutsPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -45533,22 +44914,32 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func handleSelectedHistory(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "handleSelectedHistory(at: Int)", parameterMatchers: matchers)) + } + + func handlePayoutAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "handlePayoutAction()", parameterMatchers: matchers)) } - func selectAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationPresenterProtocol.self, method: "selectAccount()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "reload()", parameterMatchers: matchers)) + } + + func getTimeLeftString(at index: M1) -> Cuckoo.ProtocolStubFunction<(Int), LocalizableResource?> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "getTimeLeftString(at: Int) -> LocalizableResource?", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRebondConfirmationPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardPayoutsPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -45569,21 +44960,33 @@ import SoraFoundation } @discardableResult - func confirm() -> Cuckoo.__DoNotUse<(), Void> { + func handleSelectedHistory(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("handleSelectedHistory(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func handlePayoutAction() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("handlePayoutAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectAccount() -> Cuckoo.__DoNotUse<(), Void> { + func reload() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func getTimeLeftString(at index: M1) -> Cuckoo.__DoNotUse<(Int), LocalizableResource?> where M1.MatchedType == Int { + let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] + return cuckoo_manager.verify("getTimeLeftString(at: Int) -> LocalizableResource?", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRebondConfirmationPresenterProtocolStub: StakingRebondConfirmationPresenterProtocol { + class StakingRewardPayoutsPresenterProtocolStub: StakingRewardPayoutsPresenterProtocol { @@ -45597,33 +45000,45 @@ import SoraFoundation - func confirm() { + func handleSelectedHistory(at index: Int) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectAccount() { + func handlePayoutAction() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func reload() { return DefaultValueRegistry.defaultValue(for: (Void).self) } + + + func getTimeLeftString(at index: Int) -> LocalizableResource? { + return DefaultValueRegistry.defaultValue(for: (LocalizableResource?).self) + } + } - class MockStakingRebondConfirmationInteractorInputProtocol: StakingRebondConfirmationInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardPayoutsInteractorInputProtocol: StakingRewardPayoutsInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRebondConfirmationInteractorInputProtocol + typealias MocksType = StakingRewardPayoutsInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingRebondConfirmationInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingRebondConfirmationInteractorInputProtocol + typealias Stubbing = __StubbingProxy_StakingRewardPayoutsInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingRewardPayoutsInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRebondConfirmationInteractorInputProtocol? + private var __defaultImplStub: StakingRewardPayoutsInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingRebondConfirmationInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardPayoutsInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -45651,36 +45066,21 @@ import SoraFoundation - func submit(for amount: Decimal) { - - return cuckoo_manager.call("submit(for: Decimal)", - parameters: (amount), - escapingParameters: (amount), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.submit(for: amount)) - - } - - - - func estimateFee(for amount: Decimal) { + func reload() { - return cuckoo_manager.call("estimateFee(for: Decimal)", - parameters: (amount), - escapingParameters: (amount), + return cuckoo_manager.call("reload()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFee(for: amount)) + defaultCall: __defaultImplStub!.reload()) } - struct __StubbingProxy_StakingRebondConfirmationInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardPayoutsInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -45690,22 +45090,17 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func submit(for amount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorInputProtocol.self, method: "submit(for: Decimal)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func estimateFee(for amount: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorInputProtocol.self, method: "estimateFee(for: Decimal)", parameterMatchers: matchers)) + func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorInputProtocol.self, method: "reload()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRebondConfirmationInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardPayoutsInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -45726,21 +45121,15 @@ import SoraFoundation } @discardableResult - func submit(for amount: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] - return cuckoo_manager.verify("submit(for: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func estimateFee(for amount: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: amount) { $0 }] - return cuckoo_manager.verify("estimateFee(for: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRebondConfirmationInteractorInputProtocolStub: StakingRebondConfirmationInteractorInputProtocol { + class StakingRewardPayoutsInteractorInputProtocolStub: StakingRewardPayoutsInteractorInputProtocol { @@ -45754,13 +45143,7 @@ import SoraFoundation - func submit(for amount: Decimal) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func estimateFee(for amount: Decimal) { + func reload() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -45768,19 +45151,19 @@ import SoraFoundation - class MockStakingRebondConfirmationInteractorOutputProtocol: StakingRebondConfirmationInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockStakingRewardPayoutsInteractorOutputProtocol: StakingRewardPayoutsInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRebondConfirmationInteractorOutputProtocol + typealias MocksType = StakingRewardPayoutsInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingRebondConfirmationInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingRebondConfirmationInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_StakingRewardPayoutsInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingRewardPayoutsInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRebondConfirmationInteractorOutputProtocol? + private var __defaultImplStub: StakingRewardPayoutsInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingRebondConfirmationInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: StakingRewardPayoutsInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -45793,111 +45176,193 @@ import SoraFoundation - func didReceiveStakingLedger(result: Result) { + func didReceive(result: Result) { - return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", + return cuckoo_manager.call("didReceive(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) + defaultCall: __defaultImplStub!.didReceive(result: result)) } - func didReceiveAccountInfo(result: Result) { + func didReceive(priceResult: Result) { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceive(priceResult: Result)", + parameters: (priceResult), + escapingParameters: (priceResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.didReceive(priceResult: priceResult)) } - func didReceivePriceData(result: Result) { + func didReceive(eraCountdownResult: Result) { - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceive(eraCountdownResult: Result)", + parameters: (eraCountdownResult), + escapingParameters: (eraCountdownResult), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + defaultCall: __defaultImplStub!.didReceive(eraCountdownResult: eraCountdownResult)) } + + struct __StubbingProxy_StakingRewardPayoutsInteractorOutputProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func didReceive(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorOutputProtocol.self, method: "didReceive(result: Result)", parameterMatchers: matchers)) + } + + func didReceive(priceResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorOutputProtocol.self, method: "didReceive(priceResult: Result)", parameterMatchers: matchers)) + } + + func didReceive(eraCountdownResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: eraCountdownResult) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorOutputProtocol.self, method: "didReceive(eraCountdownResult: Result)", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_StakingRewardPayoutsInteractorOutputProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func didReceive(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceive(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(priceResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] + return cuckoo_manager.verify("didReceive(priceResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceive(eraCountdownResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: eraCountdownResult) { $0 }] + return cuckoo_manager.verify("didReceive(eraCountdownResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class StakingRewardPayoutsInteractorOutputProtocolStub: StakingRewardPayoutsInteractorOutputProtocol { + + + + + + + + func didReceive(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + - func didReceiveFee(result: Result) { - - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) - + func didReceive(priceResult: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveController(result: Result) { - - return cuckoo_manager.call("didReceiveController(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveController(result: result)) - + func didReceive(eraCountdownResult: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + +} + + + + class MockStakingRewardPayoutsWireframeProtocol: StakingRewardPayoutsWireframeProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = StakingRewardPayoutsWireframeProtocol + + typealias Stubbing = __StubbingProxy_StakingRewardPayoutsWireframeProtocol + typealias Verification = __VerificationProxy_StakingRewardPayoutsWireframeProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: StakingRewardPayoutsWireframeProtocol? + + func enableDefaultImplementation(_ stub: StakingRewardPayoutsWireframeProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func didReceiveStashItem(result: Result) { + + + + + func showRewardDetails(from view: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown) { - return cuckoo_manager.call("didReceiveStashItem(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("showRewardDetails(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown)", + parameters: (view, payoutInfo, historyDepth, eraCountdown), + escapingParameters: (view, payoutInfo, historyDepth, eraCountdown), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) + defaultCall: __defaultImplStub!.showRewardDetails(from: view, payoutInfo: payoutInfo, historyDepth: historyDepth, eraCountdown: eraCountdown)) } - func didSubmitRebonding(result: Result) { + func showPayoutConfirmation(for payouts: [PayoutInfo], from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("didSubmitRebonding(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("showPayoutConfirmation(for: [PayoutInfo], from: ControllerBackedProtocol?)", + parameters: (payouts, view), + escapingParameters: (payouts, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didSubmitRebonding(result: result)) + defaultCall: __defaultImplStub!.showPayoutConfirmation(for: payouts, from: view)) } - struct __StubbingProxy_StakingRebondConfirmationInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingRewardPayoutsWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -45905,44 +45370,19 @@ import SoraFoundation } - func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + func showRewardDetails(from view: M1, payoutInfo: M2, historyDepth: M3, eraCountdown: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, PayoutInfo, UInt32, EraCountdown)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == PayoutInfo, M3.MatchedType == UInt32, M4.MatchedType == EraCountdown { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, PayoutInfo, UInt32, EraCountdown)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: payoutInfo) { $0.1 }, wrap(matchable: historyDepth) { $0.2 }, wrap(matchable: eraCountdown) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsWireframeProtocol.self, method: "showRewardDetails(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown)", parameterMatchers: matchers)) } - func didSubmitRebonding(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationInteractorOutputProtocol.self, method: "didSubmitRebonding(result: Result)", parameterMatchers: matchers)) + func showPayoutConfirmation(for payouts: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<([PayoutInfo], ControllerBackedProtocol?)> where M1.MatchedType == [PayoutInfo], M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<([PayoutInfo], ControllerBackedProtocol?)>] = [wrap(matchable: payouts) { $0.0 }, wrap(matchable: view) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsWireframeProtocol.self, method: "showPayoutConfirmation(for: [PayoutInfo], from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRebondConfirmationInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingRewardPayoutsWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -45957,51 +45397,21 @@ import SoraFoundation @discardableResult - func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showRewardDetails(from view: M1, payoutInfo: M2, historyDepth: M3, eraCountdown: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, PayoutInfo, UInt32, EraCountdown), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == PayoutInfo, M3.MatchedType == UInt32, M4.MatchedType == EraCountdown { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, PayoutInfo, UInt32, EraCountdown)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: payoutInfo) { $0.1 }, wrap(matchable: historyDepth) { $0.2 }, wrap(matchable: eraCountdown) { $0.3 }] + return cuckoo_manager.verify("showRewardDetails(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didSubmitRebonding(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didSubmitRebonding(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showPayoutConfirmation(for payouts: M1, from view: M2) -> Cuckoo.__DoNotUse<([PayoutInfo], ControllerBackedProtocol?), Void> where M1.MatchedType == [PayoutInfo], M2.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<([PayoutInfo], ControllerBackedProtocol?)>] = [wrap(matchable: payouts) { $0.0 }, wrap(matchable: view) { $0.1 }] + return cuckoo_manager.verify("showPayoutConfirmation(for: [PayoutInfo], from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRebondConfirmationInteractorOutputProtocolStub: StakingRebondConfirmationInteractorOutputProtocol { + class StakingRewardPayoutsWireframeProtocolStub: StakingRewardPayoutsWireframeProtocol { @@ -46009,43 +45419,13 @@ import SoraFoundation - func didReceiveStakingLedger(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAccountInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceivePriceData(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveController(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveStashItem(result: Result) { + func showRewardDetails(from view: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didSubmitRebonding(result: Result) { + func showPayoutConfirmation(for payouts: [PayoutInfo], from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -46053,19 +45433,19 @@ import SoraFoundation - class MockStakingRebondConfirmationWireframeProtocol: StakingRebondConfirmationWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingPayoutViewModelFactoryProtocol: StakingPayoutViewModelFactoryProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRebondConfirmationWireframeProtocol + typealias MocksType = StakingPayoutViewModelFactoryProtocol - typealias Stubbing = __StubbingProxy_StakingRebondConfirmationWireframeProtocol - typealias Verification = __VerificationProxy_StakingRebondConfirmationWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingPayoutViewModelFactoryProtocol + typealias Verification = __VerificationProxy_StakingPayoutViewModelFactoryProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRebondConfirmationWireframeProtocol? + private var __defaultImplStub: StakingPayoutViewModelFactoryProtocol? - func enableDefaultImplementation(_ stub: StakingRebondConfirmationWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingPayoutViewModelFactoryProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -46078,51 +45458,36 @@ import SoraFoundation - func complete(from view: StakingRebondConfirmationViewProtocol?) { - - return cuckoo_manager.call("complete(from: StakingRebondConfirmationViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.complete(from: view)) - - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource", + parameters: (payoutsInfo, priceData, eraCountdown), + escapingParameters: (payoutsInfo, priceData, eraCountdown), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.createPayoutsViewModel(payoutsInfo: payoutsInfo, priceData: priceData, eraCountdown: eraCountdown)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func timeLeftString(at index: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("timeLeftString(at: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource", + parameters: (index, payoutsInfo, eraCountdown), + escapingParameters: (index, payoutsInfo, eraCountdown), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.timeLeftString(at: index, payoutsInfo: payoutsInfo, eraCountdown: eraCountdown)) } - struct __StubbingProxy_StakingRebondConfirmationWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingPayoutViewModelFactoryProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -46130,24 +45495,19 @@ import SoraFoundation } - func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRebondConfirmationViewProtocol?)> where M1.OptionalMatchedType == StakingRebondConfirmationViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingRebondConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationWireframeProtocol.self, method: "complete(from: StakingRebondConfirmationViewProtocol?)", parameterMatchers: matchers)) - } - - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func createPayoutsViewModel(payoutsInfo: M1, priceData: M2, eraCountdown: M3) -> Cuckoo.ProtocolStubFunction<(PayoutsInfo, PriceData?, EraCountdown?), LocalizableResource> where M1.MatchedType == PayoutsInfo, M2.OptionalMatchedType == PriceData, M3.OptionalMatchedType == EraCountdown { + let matchers: [Cuckoo.ParameterMatcher<(PayoutsInfo, PriceData?, EraCountdown?)>] = [wrap(matchable: payoutsInfo) { $0.0 }, wrap(matchable: priceData) { $0.1 }, wrap(matchable: eraCountdown) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutViewModelFactoryProtocol.self, method: "createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondConfirmationWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func timeLeftString(at index: M1, payoutsInfo: M2, eraCountdown: M3) -> Cuckoo.ProtocolStubFunction<(Int, PayoutsInfo, EraCountdown?), LocalizableResource> where M1.MatchedType == Int, M2.MatchedType == PayoutsInfo, M3.OptionalMatchedType == EraCountdown { + let matchers: [Cuckoo.ParameterMatcher<(Int, PayoutsInfo, EraCountdown?)>] = [wrap(matchable: index) { $0.0 }, wrap(matchable: payoutsInfo) { $0.1 }, wrap(matchable: eraCountdown) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutViewModelFactoryProtocol.self, method: "timeLeftString(at: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRebondConfirmationWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingPayoutViewModelFactoryProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -46162,27 +45522,21 @@ import SoraFoundation @discardableResult - func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingRebondConfirmationViewProtocol?), Void> where M1.OptionalMatchedType == StakingRebondConfirmationViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingRebondConfirmationViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("complete(from: StakingRebondConfirmationViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func createPayoutsViewModel(payoutsInfo: M1, priceData: M2, eraCountdown: M3) -> Cuckoo.__DoNotUse<(PayoutsInfo, PriceData?, EraCountdown?), LocalizableResource> where M1.MatchedType == PayoutsInfo, M2.OptionalMatchedType == PriceData, M3.OptionalMatchedType == EraCountdown { + let matchers: [Cuckoo.ParameterMatcher<(PayoutsInfo, PriceData?, EraCountdown?)>] = [wrap(matchable: payoutsInfo) { $0.0 }, wrap(matchable: priceData) { $0.1 }, wrap(matchable: eraCountdown) { $0.2 }] + return cuckoo_manager.verify("createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func timeLeftString(at index: M1, payoutsInfo: M2, eraCountdown: M3) -> Cuckoo.__DoNotUse<(Int, PayoutsInfo, EraCountdown?), LocalizableResource> where M1.MatchedType == Int, M2.MatchedType == PayoutsInfo, M3.OptionalMatchedType == EraCountdown { + let matchers: [Cuckoo.ParameterMatcher<(Int, PayoutsInfo, EraCountdown?)>] = [wrap(matchable: index) { $0.0 }, wrap(matchable: payoutsInfo) { $0.1 }, wrap(matchable: eraCountdown) { $0.2 }] + return cuckoo_manager.verify("timeLeftString(at: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRebondConfirmationWireframeProtocolStub: StakingRebondConfirmationWireframeProtocol { + class StakingPayoutViewModelFactoryProtocolStub: StakingPayoutViewModelFactoryProtocol { @@ -46190,20 +45544,14 @@ import SoraFoundation - func complete(from view: StakingRebondConfirmationViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource { + return DefaultValueRegistry.defaultValue(for: (LocalizableResource).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func timeLeftString(at index: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource { + return DefaultValueRegistry.defaultValue(for: (LocalizableResource).self) } } @@ -46212,24 +45560,24 @@ import SoraFoundation import Cuckoo @testable import novawallet -import CommonWallet +import BigInt import Foundation import SoraFoundation - class MockStakingRebondSetupViewProtocol: StakingRebondSetupViewProtocol, Cuckoo.ProtocolMock { + class MockStakingUnbondConfirmViewProtocol: StakingUnbondConfirmViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRebondSetupViewProtocol + typealias MocksType = StakingUnbondConfirmViewProtocol - typealias Stubbing = __StubbingProxy_StakingRebondSetupViewProtocol - typealias Verification = __VerificationProxy_StakingRebondSetupViewProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondConfirmViewProtocol + typealias Verification = __VerificationProxy_StakingUnbondConfirmViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRebondSetupViewProtocol? + private var __defaultImplStub: StakingUnbondConfirmViewProtocol? - func enableDefaultImplementation(_ stub: StakingRebondSetupViewProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondConfirmViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -46288,367 +45636,160 @@ import SoraFoundation } - - - - - - - func didReceiveAsset(viewModel: LocalizableResource) { - - return cuckoo_manager.call("didReceiveAsset(viewModel: LocalizableResource)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) - - } - - - - func didReceiveFee(viewModel: LocalizableResource?) { - - return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) - - } - - - - func didReceiveInput(viewModel: LocalizableResource) { - - return cuckoo_manager.call("didReceiveInput(viewModel: LocalizableResource)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) - - } - - - - func didReceiveTransferable(viewModel: LocalizableResource?) { - - return cuckoo_manager.call("didReceiveTransferable(viewModel: LocalizableResource?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveTransferable(viewModel: viewModel)) - - } - - - - public func applyLocalization() { - - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.applyLocalization()) - - } - - - struct __StubbingProxy_StakingRebondSetupViewProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") - } - - - func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "didReceiveAsset(viewModel: LocalizableResource)", parameterMatchers: matchers)) - } - - func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) - } - - func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "didReceiveInput(viewModel: LocalizableResource)", parameterMatchers: matchers)) - } - - func didReceiveTransferable(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "didReceiveTransferable(viewModel: LocalizableResource?)", parameterMatchers: matchers)) - } - - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_StakingRebondSetupViewProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - - @discardableResult - func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveAsset(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveInput(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveTransferable(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveTransferable(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class StakingRebondSetupViewProtocolStub: StakingRebondSetupViewProtocol { - - var isSetup: Bool { + var loadableContentView: UIView! { get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) } } - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } - - - public var localizationManager: LocalizationManagerProtocol? { + var shouldDisableInteractionWhenLoading: Bool { get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) } - set { } - - } - - - - - - - - func didReceiveAsset(viewModel: LocalizableResource) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(viewModel: LocalizableResource?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveInput(viewModel: LocalizableResource) { - return DefaultValueRegistry.defaultValue(for: (Void).self) } + - - func didReceiveTransferable(viewModel: LocalizableResource?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - public func applyLocalization() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel) { + + return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) + } -} - - - - class MockStakingRebondSetupPresenterProtocol: StakingRebondSetupPresenterProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRebondSetupPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingRebondSetupPresenterProtocol - typealias Verification = __VerificationProxy_StakingRebondSetupPresenterProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: StakingRebondSetupPresenterProtocol? - - func enableDefaultImplementation(_ stub: StakingRebondSetupPresenterProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func didReceiveAmount(viewModel: LocalizableResource) { + + return cuckoo_manager.call("didReceiveAmount(viewModel: LocalizableResource)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveAmount(viewModel: viewModel)) + } - - - + func didReceiveFee(viewModel: LocalizableResource?) { + + return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) + + } - func setup() { + func didReceiveBonding(duration: LocalizableResource) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveBonding(duration: LocalizableResource)", + parameters: (duration), + escapingParameters: (duration), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.didReceiveBonding(duration: duration)) } - func selectAmountPercentage(_ percentage: Float) { + func didSetShouldResetRewardsDestination(value: Bool) { - return cuckoo_manager.call("selectAmountPercentage(_: Float)", - parameters: (percentage), - escapingParameters: (percentage), + return cuckoo_manager.call("didSetShouldResetRewardsDestination(value: Bool)", + parameters: (value), + escapingParameters: (value), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectAmountPercentage(percentage)) + defaultCall: __defaultImplStub!.didSetShouldResetRewardsDestination(value: value)) } - func updateAmount(_ newValue: Decimal) { + public func applyLocalization() { - return cuckoo_manager.call("updateAmount(_: Decimal)", - parameters: (newValue), - escapingParameters: (newValue), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.updateAmount(newValue)) + defaultCall: __defaultImplStub!.applyLocalization()) } - func proceed() { + func didStartLoading() { - return cuckoo_manager.call("proceed()", + return cuckoo_manager.call("didStartLoading()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.didStartLoading()) } - func close() { + func didStopLoading() { - return cuckoo_manager.call("close()", + return cuckoo_manager.call("didStopLoading()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close()) + defaultCall: __defaultImplStub!.didStopLoading()) } - struct __StubbingProxy_StakingRebondSetupPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingUnbondConfirmViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -46656,34 +45797,74 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func selectAmountPercentage(_ percentage: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Float)> where M1.MatchedType == Float { - let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "selectAmountPercentage(_: Float)", parameterMatchers: matchers)) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func updateAmount(_ newValue: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "updateAmount(_: Decimal)", parameterMatchers: matchers)) + + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") + } + + + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingUnbondConfirmViewModel)> where M1.MatchedType == StakingUnbondConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel)", parameterMatchers: matchers)) + } + + func didReceiveAmount(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didReceiveAmount(viewModel: LocalizableResource)", parameterMatchers: matchers)) + } + + func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + } + + func didReceiveBonding(duration: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: duration) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didReceiveBonding(duration: LocalizableResource)", parameterMatchers: matchers)) + } + + func didSetShouldResetRewardsDestination(value: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: value) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didSetShouldResetRewardsDestination(value: Bool)", parameterMatchers: matchers)) + } + + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } - func close() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupPresenterProtocol.self, method: "close()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + } + + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRebondSetupPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondConfirmViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -46695,199 +45876,182 @@ import SoraFoundation } + + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingUnbondConfirmViewModel), Void> where M1.MatchedType == StakingUnbondConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectAmountPercentage(_ percentage: M1) -> Cuckoo.__DoNotUse<(Float), Void> where M1.MatchedType == Float { - let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] - return cuckoo_manager.verify("selectAmountPercentage(_: Float)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAmount(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveAmount(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func updateAmount(_ newValue: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] - return cuckoo_manager.verify("updateAmount(_: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { + func didReceiveBonding(duration: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: duration) { $0 }] + return cuckoo_manager.verify("didReceiveBonding(duration: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didSetShouldResetRewardsDestination(value: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: value) { $0 }] + return cuckoo_manager.verify("didSetShouldResetRewardsDestination(value: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func close() -> Cuckoo.__DoNotUse<(), Void> { + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("close()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRebondSetupPresenterProtocolStub: StakingRebondSetupPresenterProtocol { - - + class StakingUnbondConfirmViewProtocolStub: StakingUnbondConfirmViewProtocol { + - + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + - - func selectAmountPercentage(_ percentage: Float) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + } + - - func updateAmount(_ newValue: Decimal) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + } + - - func proceed() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + } + + + + - func close() { + func didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockStakingRebondSetupInteractorInputProtocol: StakingRebondSetupInteractorInputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRebondSetupInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingRebondSetupInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingRebondSetupInteractorInputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: StakingRebondSetupInteractorInputProtocol? - - func enableDefaultImplementation(_ stub: StakingRebondSetupInteractorInputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func didReceiveAmount(viewModel: LocalizableResource) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - + func didReceiveFee(viewModel: LocalizableResource?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - + func didReceiveBonding(duration: LocalizableResource) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func estimateFee() { - - return cuckoo_manager.call("estimateFee()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.estimateFee()) - + func didSetShouldResetRewardsDestination(value: Bool) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - struct __StubbingProxy_StakingRebondSetupInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_StakingRebondSetupInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class StakingRebondSetupInteractorInputProtocolStub: StakingRebondSetupInteractorInputProtocol { - - + public func applyLocalization() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func setup() { + func didStartLoading() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func estimateFee() { + func didStopLoading() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -46895,19 +46059,19 @@ import SoraFoundation - class MockStakingRebondSetupInteractorOutputProtocol: StakingRebondSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockStakingUnbondConfirmPresenterProtocol: StakingUnbondConfirmPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRebondSetupInteractorOutputProtocol + typealias MocksType = StakingUnbondConfirmPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingRebondSetupInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingRebondSetupInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondConfirmPresenterProtocol + typealias Verification = __VerificationProxy_StakingUnbondConfirmPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRebondSetupInteractorOutputProtocol? + private var __defaultImplStub: StakingUnbondConfirmPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingRebondSetupInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondConfirmPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -46920,136 +46084,76 @@ import SoraFoundation - func didReceiveStakingLedger(result: Result) { - - return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) - - } - - - - func didReceiveFee(result: Result) { - - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) - - } - - - - func didReceivePriceData(result: Result) { - - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) - - } - - - - func didReceiveController(result: Result) { + func setup() { - return cuckoo_manager.call("didReceiveController(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveController(result: result)) + defaultCall: __defaultImplStub!.setup()) } - func didReceiveStashItem(result: Result) { + func confirm() { - return cuckoo_manager.call("didReceiveStashItem(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("confirm()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) + defaultCall: __defaultImplStub!.confirm()) } - func didReceiveAccountInfo(result: Result) { + func selectAccount() { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("selectAccount()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.selectAccount()) } - - struct __StubbingProxy_StakingRebondSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + + struct __StubbingProxy_StakingUnbondConfirmPresenterProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager } - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) - } - func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) } - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) + func selectAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmPresenterProtocol.self, method: "selectAccount()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRebondSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondConfirmPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -47064,45 +46168,27 @@ import SoraFoundation @discardableResult - func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func confirm() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectAccount() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("selectAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRebondSetupInteractorOutputProtocolStub: StakingRebondSetupInteractorOutputProtocol { + class StakingUnbondConfirmPresenterProtocolStub: StakingUnbondConfirmPresenterProtocol { @@ -47110,37 +46196,19 @@ import SoraFoundation - func didReceiveStakingLedger(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceivePriceData(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveController(result: Result) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStashItem(result: Result) { + func confirm() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveAccountInfo(result: Result) { + func selectAccount() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -47148,19 +46216,19 @@ import SoraFoundation - class MockStakingRebondSetupWireframeProtocol: StakingRebondSetupWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingUnbondConfirmInteractorInputProtocol: StakingUnbondConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRebondSetupWireframeProtocol + typealias MocksType = StakingUnbondConfirmInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingRebondSetupWireframeProtocol - typealias Verification = __VerificationProxy_StakingRebondSetupWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondConfirmInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingUnbondConfirmInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRebondSetupWireframeProtocol? + private var __defaultImplStub: StakingUnbondConfirmInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingRebondSetupWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondConfirmInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -47173,66 +46241,51 @@ import SoraFoundation - func proceed(view parameter0: StakingRebondSetupViewProtocol?, amount parameter1: Decimal) { - - return cuckoo_manager.call("proceed(view: StakingRebondSetupViewProtocol?, amount: Decimal)", - parameters: (parameter0, parameter1), - escapingParameters: (parameter0, parameter1), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.proceed(view: parameter0, amount: parameter1)) - - } - - - - func close(view: StakingRebondSetupViewProtocol?) { + func setup() { - return cuckoo_manager.call("close(view: StakingRebondSetupViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close(view: view)) + defaultCall: __defaultImplStub!.setup()) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func submit(for amount: Decimal, resettingRewardDestination: Bool, chilling: Bool) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("submit(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", + parameters: (amount, resettingRewardDestination, chilling), + escapingParameters: (amount, resettingRewardDestination, chilling), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.submit(for: amount, resettingRewardDestination: resettingRewardDestination, chilling: chilling)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func estimateFee(for amount: Decimal, resettingRewardDestination: Bool, chilling: Bool) { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("estimateFee(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", + parameters: (amount, resettingRewardDestination, chilling), + escapingParameters: (amount, resettingRewardDestination, chilling), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.estimateFee(for: amount, resettingRewardDestination: resettingRewardDestination, chilling: chilling)) } - struct __StubbingProxy_StakingRebondSetupWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingUnbondConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -47240,29 +46293,24 @@ import SoraFoundation } - func proceed(view parameter0: M1, amount parameter1: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRebondSetupViewProtocol?, Decimal)> where M1.OptionalMatchedType == StakingRebondSetupViewProtocol, M2.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(StakingRebondSetupViewProtocol?, Decimal)>] = [wrap(matchable: parameter0) { $0.0 }, wrap(matchable: parameter1) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupWireframeProtocol.self, method: "proceed(view: StakingRebondSetupViewProtocol?, amount: Decimal)", parameterMatchers: matchers)) - } - - func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRebondSetupViewProtocol?)> where M1.OptionalMatchedType == StakingRebondSetupViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingRebondSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupWireframeProtocol.self, method: "close(view: StakingRebondSetupViewProtocol?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func submit(for amount: M1, resettingRewardDestination: M2, chilling: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal, Bool, Bool)> where M1.MatchedType == Decimal, M2.MatchedType == Bool, M3.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Decimal, Bool, Bool)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: resettingRewardDestination) { $0.1 }, wrap(matchable: chilling) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorInputProtocol.self, method: "submit(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRebondSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func estimateFee(for amount: M1, resettingRewardDestination: M2, chilling: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal, Bool, Bool)> where M1.MatchedType == Decimal, M2.MatchedType == Bool, M3.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Decimal, Bool, Bool)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: resettingRewardDestination) { $0.1 }, wrap(matchable: chilling) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorInputProtocol.self, method: "estimateFee(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRebondSetupWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -47277,33 +46325,27 @@ import SoraFoundation @discardableResult - func proceed(view parameter0: M1, amount parameter1: M2) -> Cuckoo.__DoNotUse<(StakingRebondSetupViewProtocol?, Decimal), Void> where M1.OptionalMatchedType == StakingRebondSetupViewProtocol, M2.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(StakingRebondSetupViewProtocol?, Decimal)>] = [wrap(matchable: parameter0) { $0.0 }, wrap(matchable: parameter1) { $0.1 }] - return cuckoo_manager.verify("proceed(view: StakingRebondSetupViewProtocol?, amount: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func close(view: M1) -> Cuckoo.__DoNotUse<(StakingRebondSetupViewProtocol?), Void> where M1.OptionalMatchedType == StakingRebondSetupViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingRebondSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(view: StakingRebondSetupViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func submit(for amount: M1, resettingRewardDestination: M2, chilling: M3) -> Cuckoo.__DoNotUse<(Decimal, Bool, Bool), Void> where M1.MatchedType == Decimal, M2.MatchedType == Bool, M3.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Decimal, Bool, Bool)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: resettingRewardDestination) { $0.1 }, wrap(matchable: chilling) { $0.2 }] + return cuckoo_manager.verify("submit(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee(for amount: M1, resettingRewardDestination: M2, chilling: M3) -> Cuckoo.__DoNotUse<(Decimal, Bool, Bool), Void> where M1.MatchedType == Decimal, M2.MatchedType == Bool, M3.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Decimal, Bool, Bool)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: resettingRewardDestination) { $0.1 }, wrap(matchable: chilling) { $0.2 }] + return cuckoo_manager.verify("estimateFee(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRebondSetupWireframeProtocolStub: StakingRebondSetupWireframeProtocol { + class StakingUnbondConfirmInteractorInputProtocolStub: StakingUnbondConfirmInteractorInputProtocol { @@ -47311,234 +46353,246 @@ import SoraFoundation - func proceed(view parameter0: StakingRebondSetupViewProtocol?, amount parameter1: Decimal) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func close(view: StakingRebondSetupViewProtocol?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func submit(for amount: Decimal, resettingRewardDestination: Bool, chilling: Bool) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func estimateFee(for amount: Decimal, resettingRewardDestination: Bool, chilling: Bool) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import BigInt -import Foundation -import SoraFoundation - - class MockStakingRedeemViewProtocol: StakingRedeemViewProtocol, Cuckoo.ProtocolMock { + class MockStakingUnbondConfirmInteractorOutputProtocol: StakingUnbondConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRedeemViewProtocol + typealias MocksType = StakingUnbondConfirmInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingRedeemViewProtocol - typealias Verification = __VerificationProxy_StakingRedeemViewProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondConfirmInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingUnbondConfirmInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRedeemViewProtocol? + private var __defaultImplStub: StakingUnbondConfirmInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingRedeemViewProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondConfirmInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } + + + func didReceiveStakingLedger(result: Result) { + + return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) } - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } + func didReceiveAccountInfo(result: Result) { + + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } + func didReceivePriceData(result: Result) { - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } + func didReceiveExistentialDeposit(result: Result) { + + return cuckoo_manager.call("didReceiveExistentialDeposit(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveExistentialDeposit(result: result)) } - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } + func didReceiveFee(result: Result) { + + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - - + + func didReceiveController(result: Result) { + + return cuckoo_manager.call("didReceiveController(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveController(result: result)) + + } - func didReceiveConfirmation(viewModel: StakingRedeemViewModel) { + func didReceiveStashItem(result: Result) { - return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingRedeemViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didReceiveStashItem(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) } - func didReceiveAmount(viewModel: LocalizableResource) { + func didReceivePayee(result: Result) { - return cuckoo_manager.call("didReceiveAmount(viewModel: LocalizableResource)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didReceivePayee(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAmount(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceivePayee(result: result)) } - func didReceiveFee(viewModel: LocalizableResource?) { + func didReceiveMinBonded(result: Result) { - return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didReceiveMinBonded(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveMinBonded(result: result)) } - public func applyLocalization() { + func didReceiveNomination(result: Result) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveNomination(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.didReceiveNomination(result: result)) } - func didStartLoading() { + func didReceiveBondingDuration(result: Result) { - return cuckoo_manager.call("didStartLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveBondingDuration(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStartLoading()) + defaultCall: __defaultImplStub!.didReceiveBondingDuration(result: result)) } - func didStopLoading() { + func didReceiveStakingDuration(result: Result) { - return cuckoo_manager.call("didStopLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveStakingDuration(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopLoading()) + defaultCall: __defaultImplStub!.didReceiveStakingDuration(result: result)) + + } + + + + func didSubmitUnbonding(result: Result) { + + return cuckoo_manager.call("didSubmitUnbonding(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didSubmitUnbonding(result: result)) } - struct __StubbingProxy_StakingRedeemViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingUnbondConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -47546,64 +46600,74 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") + func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) } - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) } - - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") + func didReceiveExistentialDeposit(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveExistentialDeposit(result: Result)", parameterMatchers: matchers)) } + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + } - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") + func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) } + func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + } - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRedeemViewModel)> where M1.MatchedType == StakingRedeemViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingRedeemViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingRedeemViewModel)", parameterMatchers: matchers)) + func didReceivePayee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceivePayee(result: Result)", parameterMatchers: matchers)) } - func didReceiveAmount(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didReceiveAmount(viewModel: LocalizableResource)", parameterMatchers: matchers)) + func didReceiveMinBonded(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveMinBonded(result: Result)", parameterMatchers: matchers)) } - func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + func didReceiveNomination(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveNomination(result: Result)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func didReceiveBondingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveBondingDuration(result: Result)", parameterMatchers: matchers)) } - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + func didReceiveStakingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveStakingDuration(result: Result)", parameterMatchers: matchers)) } - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + func didSubmitUnbonding(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didSubmitUnbonding(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRedeemViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -47615,158 +46679,170 @@ import SoraFoundation } + - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveExistentialDeposit(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveExistentialDeposit(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - + @discardableResult + func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } @discardableResult - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingRedeemViewModel), Void> where M1.MatchedType == StakingRedeemViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingRedeemViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingRedeemViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePayee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePayee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveAmount(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveAmount(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveMinBonded(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMinBonded(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveNomination(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveNomination(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBondingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBondingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStakingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didSubmitUnbonding(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didSubmitUnbonding(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRedeemViewProtocolStub: StakingRedeemViewProtocol { - + class StakingUnbondConfirmInteractorOutputProtocolStub: StakingUnbondConfirmInteractorOutputProtocol { + - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + + + + func didReceiveStakingLedger(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - + + func didReceiveAccountInfo(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - + + func didReceivePriceData(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - + + func didReceiveExistentialDeposit(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + func didReceiveFee(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - + + func didReceiveController(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func didReceiveConfirmation(viewModel: StakingRedeemViewModel) { + func didReceiveStashItem(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveAmount(viewModel: LocalizableResource) { + func didReceivePayee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveFee(viewModel: LocalizableResource?) { + func didReceiveMinBonded(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func didReceiveNomination(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoading() { + func didReceiveBondingDuration(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStopLoading() { + func didReceiveStakingDuration(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didSubmitUnbonding(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -47774,19 +46850,19 @@ import SoraFoundation - class MockStakingRedeemPresenterProtocol: StakingRedeemPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingUnbondConfirmWireframeProtocol: StakingUnbondConfirmWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRedeemPresenterProtocol + typealias MocksType = StakingUnbondConfirmWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingRedeemPresenterProtocol - typealias Verification = __VerificationProxy_StakingRedeemPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondConfirmWireframeProtocol + typealias Verification = __VerificationProxy_StakingUnbondConfirmWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRedeemPresenterProtocol? + private var __defaultImplStub: StakingUnbondConfirmWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingRedeemPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondConfirmWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -47799,51 +46875,51 @@ import SoraFoundation - func setup() { + func complete(from view: StakingUnbondConfirmViewProtocol?) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("complete(from: StakingUnbondConfirmViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.complete(from: view)) } - func confirm() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("confirm()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.confirm()) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - func selectAccount() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("selectAccount()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectAccount()) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_StakingRedeemPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingUnbondConfirmWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -47851,24 +46927,24 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingUnbondConfirmViewProtocol?)> where M1.OptionalMatchedType == StakingUnbondConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmWireframeProtocol.self, method: "complete(from: StakingUnbondConfirmViewProtocol?)", parameterMatchers: matchers)) } - func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func selectAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemPresenterProtocol.self, method: "selectAccount()", parameterMatchers: matchers)) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRedeemPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondConfirmWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -47883,27 +46959,27 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingUnbondConfirmViewProtocol?), Void> where M1.OptionalMatchedType == StakingUnbondConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("complete(from: StakingUnbondConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func confirm() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectAccount() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRedeemPresenterProtocolStub: StakingRedeemPresenterProtocol { + class StakingUnbondConfirmWireframeProtocolStub: StakingUnbondConfirmWireframeProtocol { @@ -47911,96 +46987,201 @@ import SoraFoundation - func setup() { + func complete(from view: StakingUnbondConfirmViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func confirm() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectAccount() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet - class MockStakingRedeemInteractorInputProtocol: StakingRedeemInteractorInputProtocol, Cuckoo.ProtocolMock { +import BigInt +import CommonWallet +import Foundation +import SoraFoundation + + + class MockStakingUnbondSetupViewProtocol: StakingUnbondSetupViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRedeemInteractorInputProtocol + typealias MocksType = StakingUnbondSetupViewProtocol - typealias Stubbing = __StubbingProxy_StakingRedeemInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingRedeemInteractorInputProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondSetupViewProtocol + typealias Verification = __VerificationProxy_StakingUnbondSetupViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRedeemInteractorInputProtocol? + private var __defaultImplStub: StakingUnbondSetupViewProtocol? - func enableDefaultImplementation(_ stub: StakingRedeemInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondSetupViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } + + + + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } + + } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } + + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } + + } + - func setup() { + func didReceiveAsset(viewModel: LocalizableResource) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveAsset(viewModel: LocalizableResource)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) } - func submitForStash(_ stashAddress: AccountAddress) { + func didReceiveFee(viewModel: LocalizableResource?) { - return cuckoo_manager.call("submitForStash(_: AccountAddress)", - parameters: (stashAddress), - escapingParameters: (stashAddress), + return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.submitForStash(stashAddress)) + defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) } - func estimateFeeForStash(_ stashAddress: AccountAddress) { + func didReceiveInput(viewModel: LocalizableResource) { - return cuckoo_manager.call("estimateFeeForStash(_: AccountAddress)", - parameters: (stashAddress), - escapingParameters: (stashAddress), + return cuckoo_manager.call("didReceiveInput(viewModel: LocalizableResource)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFeeForStash(stashAddress)) + defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) + + } + + + + func didReceiveTransferable(viewModel: LocalizableResource?) { + + return cuckoo_manager.call("didReceiveTransferable(viewModel: LocalizableResource?)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveTransferable(viewModel: viewModel)) + + } + + + + func didReceiveBonding(duration: LocalizableResource) { + + return cuckoo_manager.call("didReceiveBonding(duration: LocalizableResource)", + parameters: (duration), + escapingParameters: (duration), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveBonding(duration: duration)) + + } + + + + public func applyLocalization() { + + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.applyLocalization()) } - struct __StubbingProxy_StakingRedeemInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingUnbondSetupViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -48008,24 +47189,54 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func submitForStash(_ stashAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: stashAddress) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorInputProtocol.self, method: "submitForStash(_: AccountAddress)", parameterMatchers: matchers)) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func estimateFeeForStash(_ stashAddress: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: stashAddress) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorInputProtocol.self, method: "estimateFeeForStash(_: AccountAddress)", parameterMatchers: matchers)) + + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") + } + + + func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveAsset(viewModel: LocalizableResource)", parameterMatchers: matchers)) + } + + func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + } + + func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveInput(viewModel: LocalizableResource)", parameterMatchers: matchers)) + } + + func didReceiveTransferable(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveTransferable(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + } + + func didReceiveBonding(duration: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: duration) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveBonding(duration: LocalizableResource)", parameterMatchers: matchers)) + } + + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRedeemInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondSetupViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -48037,30 +47248,92 @@ import SoraFoundation } + + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveAsset(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func submitForStash(_ stashAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: stashAddress) { $0 }] - return cuckoo_manager.verify("submitForStash(_: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func estimateFeeForStash(_ stashAddress: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { - let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: stashAddress) { $0 }] - return cuckoo_manager.verify("estimateFeeForStash(_: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveInput(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveTransferable(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveTransferable(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveBonding(duration: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { + let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: duration) { $0 }] + return cuckoo_manager.verify("didReceiveBonding(duration: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRedeemInteractorInputProtocolStub: StakingRedeemInteractorInputProtocol { + class StakingUnbondSetupViewProtocolStub: StakingUnbondSetupViewProtocol { + + + + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + + + + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + + } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } @@ -48068,19 +47341,37 @@ import SoraFoundation - func setup() { + func didReceiveAsset(viewModel: LocalizableResource) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func submitForStash(_ stashAddress: AccountAddress) { + func didReceiveFee(viewModel: LocalizableResource?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func estimateFeeForStash(_ stashAddress: AccountAddress) { + func didReceiveInput(viewModel: LocalizableResource) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveTransferable(viewModel: LocalizableResource?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveBonding(duration: LocalizableResource) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -48088,19 +47379,19 @@ import SoraFoundation - class MockStakingRedeemInteractorOutputProtocol: StakingRedeemInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockStakingUnbondSetupPresenterProtocol: StakingUnbondSetupPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRedeemInteractorOutputProtocol + typealias MocksType = StakingUnbondSetupPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingRedeemInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingRedeemInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondSetupPresenterProtocol + typealias Verification = __VerificationProxy_StakingUnbondSetupPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRedeemInteractorOutputProtocol? + private var __defaultImplStub: StakingUnbondSetupPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingRedeemInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondSetupPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -48113,141 +47404,81 @@ import SoraFoundation - func didReceiveStakingLedger(result: Result) { - - return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) - - } - - - - func didReceiveAccountInfo(result: Result) { - - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) - - } - - - - func didReceivePriceData(result: Result) { - - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) - - } - - - - func didReceiveExistentialDeposit(result: Result) { - - return cuckoo_manager.call("didReceiveExistentialDeposit(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveExistentialDeposit(result: result)) - - } - - - - func didReceiveFee(result: Result) { + func setup() { - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + defaultCall: __defaultImplStub!.setup()) } - func didReceiveController(result: Result) { + func selectAmountPercentage(_ percentage: Float) { - return cuckoo_manager.call("didReceiveController(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("selectAmountPercentage(_: Float)", + parameters: (percentage), + escapingParameters: (percentage), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveController(result: result)) + defaultCall: __defaultImplStub!.selectAmountPercentage(percentage)) } - func didReceiveStashItem(result: Result) { + func updateAmount(_ newValue: Decimal) { - return cuckoo_manager.call("didReceiveStashItem(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("updateAmount(_: Decimal)", + parameters: (newValue), + escapingParameters: (newValue), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) + defaultCall: __defaultImplStub!.updateAmount(newValue)) } - func didReceiveActiveEra(result: Result) { + func proceed() { - return cuckoo_manager.call("didReceiveActiveEra(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("proceed()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveActiveEra(result: result)) + defaultCall: __defaultImplStub!.proceed()) } - func didSubmitRedeeming(result: Result) { + func close() { - return cuckoo_manager.call("didSubmitRedeeming(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("close()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didSubmitRedeeming(result: result)) + defaultCall: __defaultImplStub!.close()) } - struct __StubbingProxy_StakingRedeemInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingUnbondSetupPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -48255,54 +47486,34 @@ import SoraFoundation } - func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveExistentialDeposit(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveExistentialDeposit(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) + func selectAmountPercentage(_ percentage: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Float)> where M1.MatchedType == Float { + let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "selectAmountPercentage(_: Float)", parameterMatchers: matchers)) } - func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + func updateAmount(_ newValue: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "updateAmount(_: Decimal)", parameterMatchers: matchers)) } - func didReceiveActiveEra(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didReceiveActiveEra(result: Result)", parameterMatchers: matchers)) + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } - func didSubmitRedeeming(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemInteractorOutputProtocol.self, method: "didSubmitRedeeming(result: Result)", parameterMatchers: matchers)) + func close() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "close()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRedeemInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondSetupPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -48317,63 +47528,39 @@ import SoraFoundation @discardableResult - func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveExistentialDeposit(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveExistentialDeposit(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectAmountPercentage(_ percentage: M1) -> Cuckoo.__DoNotUse<(Float), Void> where M1.MatchedType == Float { + let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] + return cuckoo_manager.verify("selectAmountPercentage(_: Float)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func updateAmount(_ newValue: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] + return cuckoo_manager.verify("updateAmount(_: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveActiveEra(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveActiveEra(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceed() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didSubmitRedeeming(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didSubmitRedeeming(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func close() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("close()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRedeemInteractorOutputProtocolStub: StakingRedeemInteractorOutputProtocol { + class StakingUnbondSetupPresenterProtocolStub: StakingUnbondSetupPresenterProtocol { @@ -48381,55 +47568,31 @@ import SoraFoundation - func didReceiveStakingLedger(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAccountInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceivePriceData(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveExistentialDeposit(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(result: Result) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveController(result: Result) { + func selectAmountPercentage(_ percentage: Float) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStashItem(result: Result) { + func updateAmount(_ newValue: Decimal) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveActiveEra(result: Result) { + func proceed() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didSubmitRedeeming(result: Result) { + func close() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -48437,19 +47600,19 @@ import SoraFoundation - class MockStakingRedeemWireframeProtocol: StakingRedeemWireframeProtocol, Cuckoo.ProtocolMock { + class MockStakingUnbondSetupInteractorInputProtocol: StakingUnbondSetupInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRedeemWireframeProtocol + typealias MocksType = StakingUnbondSetupInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingRedeemWireframeProtocol - typealias Verification = __VerificationProxy_StakingRedeemWireframeProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondSetupInteractorInputProtocol + typealias Verification = __VerificationProxy_StakingUnbondSetupInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRedeemWireframeProtocol? + private var __defaultImplStub: StakingUnbondSetupInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingRedeemWireframeProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondSetupInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -48462,51 +47625,36 @@ import SoraFoundation - func complete(from view: StakingRedeemViewProtocol?) { - - return cuckoo_manager.call("complete(from: StakingRedeemViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.complete(from: view)) - - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func setup() { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.setup()) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func estimateFee() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("estimateFee()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.estimateFee()) } - struct __StubbingProxy_StakingRedeemWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingUnbondSetupInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -48514,24 +47662,19 @@ import SoraFoundation } - func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRedeemViewProtocol?)> where M1.OptionalMatchedType == StakingRedeemViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingRedeemViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemWireframeProtocol.self, method: "complete(from: StakingRedeemViewProtocol?)", parameterMatchers: matchers)) - } - - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRedeemWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRedeemWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondSetupInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -48546,27 +47689,21 @@ import SoraFoundation @discardableResult - func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingRedeemViewProtocol?), Void> where M1.OptionalMatchedType == StakingRedeemViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingRedeemViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("complete(from: StakingRedeemViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRedeemWireframeProtocolStub: StakingRedeemWireframeProtocol { + class StakingUnbondSetupInteractorInputProtocolStub: StakingUnbondSetupInteractorInputProtocol { @@ -48574,211 +47711,180 @@ import SoraFoundation - func complete(from view: StakingRedeemViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func estimateFee() { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import SoraFoundation - - class MockStakingRewardDestConfirmViewProtocol: StakingRewardDestConfirmViewProtocol, Cuckoo.ProtocolMock { + class MockStakingUnbondSetupInteractorOutputProtocol: StakingUnbondSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDestConfirmViewProtocol + typealias MocksType = StakingUnbondSetupInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmViewProtocol - typealias Verification = __VerificationProxy_StakingRewardDestConfirmViewProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondSetupInteractorOutputProtocol + typealias Verification = __VerificationProxy_StakingUnbondSetupInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDestConfirmViewProtocol? + private var __defaultImplStub: StakingUnbondSetupInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDestConfirmViewProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondSetupInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } + - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } + func didReceiveStakingLedger(result: Result) { + + return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) } - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } + func didReceiveAccountInfo(result: Result) { - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - var loadableContentView: UIView! { - get { - return cuckoo_manager.getter("loadableContentView", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.loadableContentView) - } + func didReceivePriceData(result: Result) { + + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - var shouldDisableInteractionWhenLoading: Bool { - get { - return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) - } + func didReceiveBondingDuration(result: Result) { + + return cuckoo_manager.call("didReceiveBondingDuration(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveBondingDuration(result: result)) } - - - - - func didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel) { + func didReceiveExistentialDeposit(result: Result) { - return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didReceiveExistentialDeposit(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveExistentialDeposit(result: result)) } - func didReceiveFee(viewModel: LocalizableResource?) { + func didReceiveFee(result: Result) { - return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - public func applyLocalization() { + func didReceiveController(result: Result) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveController(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.didReceiveController(result: result)) } - func didStartLoading() { + func didReceiveStashItem(result: Result) { - return cuckoo_manager.call("didStartLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveStashItem(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStartLoading()) + defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) } - func didStopLoading() { + func didReceiveStakingDuration(result: Result) { - return cuckoo_manager.call("didStopLoading()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveStakingDuration(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didStopLoading()) + defaultCall: __defaultImplStub!.didReceiveStakingDuration(result: result)) } - struct __StubbingProxy_StakingRewardDestConfirmViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingUnbondSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -48786,59 +47892,54 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") + func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) } - - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView") + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) } - - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") + func didReceiveBondingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveBondingDuration(result: Result)", parameterMatchers: matchers)) } - - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRewardDestConfirmViewModel)> where M1.MatchedType == StakingRewardDestConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel)", parameterMatchers: matchers)) + func didReceiveExistentialDeposit(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveExistentialDeposit(result: Result)", parameterMatchers: matchers)) } - func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) } - func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) } - func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + func didReceiveStakingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveStakingDuration(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDestConfirmViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -48850,146 +47951,122 @@ import SoraFoundation } + - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveBondingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBondingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - - @discardableResult - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingRewardDestConfirmViewModel), Void> where M1.MatchedType == StakingRewardDestConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveExistentialDeposit(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveExistentialDeposit(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveStakingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveStakingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDestConfirmViewProtocolStub: StakingRewardDestConfirmViewProtocol { - - + class StakingUnbondSetupInteractorOutputProtocolStub: StakingUnbondSetupInteractorOutputProtocol { - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - - } - + + - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - - } - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - + func didReceiveStakingLedger(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var loadableContentView: UIView! { - get { - return DefaultValueRegistry.defaultValue(for: (UIView?).self) - } - + + func didReceiveAccountInfo(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var shouldDisableInteractionWhenLoading: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + func didReceivePriceData(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - + + func didReceiveBondingDuration(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func didReceiveConfirmation(viewModel: StakingRewardDestConfirmViewModel) { + func didReceiveExistentialDeposit(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveFee(viewModel: LocalizableResource?) { + func didReceiveFee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func didReceiveController(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStartLoading() { + func didReceiveStashItem(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didStopLoading() { + func didReceiveStakingDuration(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -48997,19 +48074,19 @@ import SoraFoundation - class MockStakingRewardDestConfirmPresenterProtocol: StakingRewardDestConfirmPresenterProtocol, Cuckoo.ProtocolMock { + class MockStakingUnbondSetupWireframeProtocol: StakingUnbondSetupWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDestConfirmPresenterProtocol + typealias MocksType = StakingUnbondSetupWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmPresenterProtocol - typealias Verification = __VerificationProxy_StakingRewardDestConfirmPresenterProtocol + typealias Stubbing = __StubbingProxy_StakingUnbondSetupWireframeProtocol + typealias Verification = __VerificationProxy_StakingUnbondSetupWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDestConfirmPresenterProtocol? + private var __defaultImplStub: StakingUnbondSetupWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDestConfirmPresenterProtocol) { + func enableDefaultImplementation(_ stub: StakingUnbondSetupWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -49022,66 +48099,66 @@ import SoraFoundation - func setup() { + func close(view: StakingUnbondSetupViewProtocol?) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("close(view: StakingUnbondSetupViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.close(view: view)) } - func confirm() { + func proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal) { - return cuckoo_manager.call("confirm()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal)", + parameters: (view, amount), + escapingParameters: (view, amount), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.confirm()) + defaultCall: __defaultImplStub!.proceed(view: view, amount: amount)) } - func presentSenderAccountOptions() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("presentSenderAccountOptions()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentSenderAccountOptions()) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - func presentPayoutAccountOptions() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("presentPayoutAccountOptions()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentPayoutAccountOptions()) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_StakingRewardDestConfirmPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_StakingUnbondSetupWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -49089,29 +48166,29 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingUnbondSetupViewProtocol?)> where M1.OptionalMatchedType == StakingUnbondSetupViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupWireframeProtocol.self, method: "close(view: StakingUnbondSetupViewProtocol?)", parameterMatchers: matchers)) } - func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + func proceed(view: M1, amount: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingUnbondSetupViewProtocol?, Decimal)> where M1.OptionalMatchedType == StakingUnbondSetupViewProtocol, M2.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondSetupViewProtocol?, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: amount) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupWireframeProtocol.self, method: "proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal)", parameterMatchers: matchers)) } - func presentSenderAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmPresenterProtocol.self, method: "presentSenderAccountOptions()", parameterMatchers: matchers)) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func presentPayoutAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmPresenterProtocol.self, method: "presentPayoutAccountOptions()", parameterMatchers: matchers)) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDestConfirmPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_StakingUnbondSetupWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -49126,33 +48203,33 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func close(view: M1) -> Cuckoo.__DoNotUse<(StakingUnbondSetupViewProtocol?), Void> where M1.OptionalMatchedType == StakingUnbondSetupViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("close(view: StakingUnbondSetupViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func confirm() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceed(view: M1, amount: M2) -> Cuckoo.__DoNotUse<(StakingUnbondSetupViewProtocol?, Decimal), Void> where M1.OptionalMatchedType == StakingUnbondSetupViewProtocol, M2.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondSetupViewProtocol?, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: amount) { $0.1 }] + return cuckoo_manager.verify("proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentSenderAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentSenderAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentPayoutAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("presentPayoutAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDestConfirmPresenterProtocolStub: StakingRewardDestConfirmPresenterProtocol { + class StakingUnbondSetupWireframeProtocolStub: StakingUnbondSetupWireframeProtocol { @@ -49160,102 +48237,105 @@ import SoraFoundation - func setup() { + func close(view: StakingUnbondSetupViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func confirm() { + func proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentSenderAccountOptions() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentPayoutAccountOptions() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet - class MockStakingRewardDestConfirmInteractorInputProtocol: StakingRewardDestConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { +import SoraFoundation + + + class MockUsernameSetupViewProtocol: UsernameSetupViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDestConfirmInteractorInputProtocol + typealias MocksType = UsernameSetupViewProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingRewardDestConfirmInteractorInputProtocol + typealias Stubbing = __StubbingProxy_UsernameSetupViewProtocol + typealias Verification = __VerificationProxy_UsernameSetupViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDestConfirmInteractorInputProtocol? + private var __defaultImplStub: UsernameSetupViewProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDestConfirmInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: UsernameSetupViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - - - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } } - func estimateFee(for rewardDestination: RewardDestination, stashItem: StashItem) { - - return cuckoo_manager.call("estimateFee(for: RewardDestination, stashItem: StashItem)", - parameters: (rewardDestination, stashItem), - escapingParameters: (rewardDestination, stashItem), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.estimateFee(for: rewardDestination, stashItem: stashItem)) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } + + + - func submit(rewardDestination: RewardDestination, for stashItem: StashItem) { + + func setInput(viewModel: InputViewModelProtocol) { - return cuckoo_manager.call("submit(rewardDestination: RewardDestination, for: StashItem)", - parameters: (rewardDestination, stashItem), - escapingParameters: (rewardDestination, stashItem), + return cuckoo_manager.call("setInput(viewModel: InputViewModelProtocol)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.submit(rewardDestination: rewardDestination, for: stashItem)) + defaultCall: __defaultImplStub!.setInput(viewModel: viewModel)) } - struct __StubbingProxy_StakingRewardDestConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_UsernameSetupViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -49263,24 +48343,24 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func estimateFee(for rewardDestination: M1, stashItem: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(RewardDestination, StashItem)> where M1.MatchedType == RewardDestination, M2.MatchedType == StashItem { - let matchers: [Cuckoo.ParameterMatcher<(RewardDestination, StashItem)>] = [wrap(matchable: rewardDestination) { $0.0 }, wrap(matchable: stashItem) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorInputProtocol.self, method: "estimateFee(for: RewardDestination, stashItem: StashItem)", parameterMatchers: matchers)) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func submit(rewardDestination: M1, for stashItem: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(RewardDestination, StashItem)> where M1.MatchedType == RewardDestination, M2.MatchedType == StashItem { - let matchers: [Cuckoo.ParameterMatcher<(RewardDestination, StashItem)>] = [wrap(matchable: rewardDestination) { $0.0 }, wrap(matchable: stashItem) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorInputProtocol.self, method: "submit(rewardDestination: RewardDestination, for: StashItem)", parameterMatchers: matchers)) + + func setInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(InputViewModelProtocol)> where M1.MatchedType == InputViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupViewProtocol.self, method: "setInput(viewModel: InputViewModelProtocol)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDestConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_UsernameSetupViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -49292,50 +48372,54 @@ import SoraFoundation } - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func estimateFee(for rewardDestination: M1, stashItem: M2) -> Cuckoo.__DoNotUse<(RewardDestination, StashItem), Void> where M1.MatchedType == RewardDestination, M2.MatchedType == StashItem { - let matchers: [Cuckoo.ParameterMatcher<(RewardDestination, StashItem)>] = [wrap(matchable: rewardDestination) { $0.0 }, wrap(matchable: stashItem) { $0.1 }] - return cuckoo_manager.verify("estimateFee(for: RewardDestination, stashItem: StashItem)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + @discardableResult - func submit(rewardDestination: M1, for stashItem: M2) -> Cuckoo.__DoNotUse<(RewardDestination, StashItem), Void> where M1.MatchedType == RewardDestination, M2.MatchedType == StashItem { - let matchers: [Cuckoo.ParameterMatcher<(RewardDestination, StashItem)>] = [wrap(matchable: rewardDestination) { $0.0 }, wrap(matchable: stashItem) { $0.1 }] - return cuckoo_manager.verify("submit(rewardDestination: RewardDestination, for: StashItem)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setInput(viewModel: M1) -> Cuckoo.__DoNotUse<(InputViewModelProtocol), Void> where M1.MatchedType == InputViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("setInput(viewModel: InputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDestConfirmInteractorInputProtocolStub: StakingRewardDestConfirmInteractorInputProtocol { - - + class UsernameSetupViewProtocolStub: UsernameSetupViewProtocol { + - + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + } + - - func estimateFee(for rewardDestination: RewardDestination, stashItem: StashItem) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } + - func submit(rewardDestination: RewardDestination, for stashItem: StashItem) { + func setInput(viewModel: InputViewModelProtocol) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -49343,19 +48427,19 @@ import SoraFoundation - class MockStakingRewardDestConfirmInteractorOutputProtocol: StakingRewardDestConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockUsernameSetupPresenterProtocol: UsernameSetupPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDestConfirmInteractorOutputProtocol + typealias MocksType = UsernameSetupPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingRewardDestConfirmInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_UsernameSetupPresenterProtocol + typealias Verification = __VerificationProxy_UsernameSetupPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDestConfirmInteractorOutputProtocol? + private var __defaultImplStub: UsernameSetupPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDestConfirmInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: UsernameSetupPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -49368,96 +48452,36 @@ import SoraFoundation - func didReceiveFee(result: Result) { - - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) - - } - - - - func didReceivePriceData(result: Result) { - - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) - - } - - - - func didReceiveStashItem(result: Result) { - - return cuckoo_manager.call("didReceiveStashItem(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) - - } - - - - func didReceiveController(result: Result) { - - return cuckoo_manager.call("didReceiveController(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveController(result: result)) - - } - - - - func didReceiveAccountInfo(result: Result) { + func setup() { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.setup()) } - func didSubmitRewardDest(result: Result) { + func proceed() { - return cuckoo_manager.call("didSubmitRewardDest(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("proceed()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didSubmitRewardDest(result: result)) + defaultCall: __defaultImplStub!.proceed()) } - struct __StubbingProxy_StakingRewardDestConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_UsernameSetupPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -49465,39 +48489,19 @@ import SoraFoundation } - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) - } - - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func didSubmitRewardDest(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmInteractorOutputProtocol.self, method: "didSubmitRewardDest(result: Result)", parameterMatchers: matchers)) + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDestConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_UsernameSetupPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -49512,45 +48516,21 @@ import SoraFoundation @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didSubmitRewardDest(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didSubmitRewardDest(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceed() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDestConfirmInteractorOutputProtocolStub: StakingRewardDestConfirmInteractorOutputProtocol { + class UsernameSetupPresenterProtocolStub: UsernameSetupPresenterProtocol { @@ -49558,37 +48538,13 @@ import SoraFoundation - func didReceiveFee(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceivePriceData(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveStashItem(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveController(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAccountInfo(result: Result) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didSubmitRewardDest(result: Result) { + func proceed() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -49596,19 +48552,19 @@ import SoraFoundation - class MockStakingRewardDestConfirmWireframeProtocol: StakingRewardDestConfirmWireframeProtocol, Cuckoo.ProtocolMock { + class MockUsernameSetupWireframeProtocol: UsernameSetupWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDestConfirmWireframeProtocol + typealias MocksType = UsernameSetupWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDestConfirmWireframeProtocol - typealias Verification = __VerificationProxy_StakingRewardDestConfirmWireframeProtocol + typealias Stubbing = __StubbingProxy_UsernameSetupWireframeProtocol + typealias Verification = __VerificationProxy_UsernameSetupWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDestConfirmWireframeProtocol? + private var __defaultImplStub: UsernameSetupWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDestConfirmWireframeProtocol) { + func enableDefaultImplementation(_ stub: UsernameSetupWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -49621,16 +48577,16 @@ import SoraFoundation - func complete(from view: StakingRewardDestConfirmViewProtocol?) { + func proceed(from view: UsernameSetupViewProtocol?, walletName: String) { - return cuckoo_manager.call("complete(from: StakingRewardDestConfirmViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("proceed(from: UsernameSetupViewProtocol?, walletName: String)", + parameters: (view, walletName), + escapingParameters: (view, walletName), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.complete(from: view)) + defaultCall: __defaultImplStub!.proceed(from: view, walletName: walletName)) } @@ -49665,7 +48621,7 @@ import SoraFoundation } - struct __StubbingProxy_StakingRewardDestConfirmWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_UsernameSetupWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -49673,24 +48629,24 @@ import SoraFoundation } - func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRewardDestConfirmViewProtocol?)> where M1.OptionalMatchedType == StakingRewardDestConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmWireframeProtocol.self, method: "complete(from: StakingRewardDestConfirmViewProtocol?)", parameterMatchers: matchers)) + func proceed(from view: M1, walletName: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(UsernameSetupViewProtocol?, String)> where M1.OptionalMatchedType == UsernameSetupViewProtocol, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(UsernameSetupViewProtocol?, String)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: walletName) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupWireframeProtocol.self, method: "proceed(from: UsernameSetupViewProtocol?, walletName: String)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDestConfirmWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_UsernameSetupWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -49705,9 +48661,9 @@ import SoraFoundation @discardableResult - func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingRewardDestConfirmViewProtocol?), Void> where M1.OptionalMatchedType == StakingRewardDestConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("complete(from: StakingRewardDestConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func proceed(from view: M1, walletName: M2) -> Cuckoo.__DoNotUse<(UsernameSetupViewProtocol?, String), Void> where M1.OptionalMatchedType == UsernameSetupViewProtocol, M2.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(UsernameSetupViewProtocol?, String)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: walletName) { $0.1 }] + return cuckoo_manager.verify("proceed(from: UsernameSetupViewProtocol?, walletName: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -49725,7 +48681,7 @@ import SoraFoundation } } - class StakingRewardDestConfirmWireframeProtocolStub: StakingRewardDestConfirmWireframeProtocol { + class UsernameSetupWireframeProtocolStub: UsernameSetupWireframeProtocol { @@ -49733,7 +48689,7 @@ import SoraFoundation - func complete(from view: StakingRewardDestConfirmViewProtocol?) { + func proceed(from view: UsernameSetupViewProtocol?, walletName: String) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -49755,147 +48711,65 @@ import SoraFoundation import Cuckoo @testable import novawallet +import BigInt import Foundation -import SoraFoundation - class MockStakingRewardDestSetupViewProtocol: StakingRewardDestSetupViewProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanContributionInteractorInputProtocol: CrowdloanContributionInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDestSetupViewProtocol + typealias MocksType = CrowdloanContributionInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDestSetupViewProtocol - typealias Verification = __VerificationProxy_StakingRewardDestSetupViewProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionInteractorInputProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDestSetupViewProtocol? + private var __defaultImplStub: CrowdloanContributionInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDestSetupViewProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - - } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } - - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } - - } - - func didReceiveFee(viewModel: LocalizableResource?) { - - return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) - - } - - - - func didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?) { - - return cuckoo_manager.call("didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveRewardDestination(viewModel: viewModel)) - - } - - - - func didCompletionAccountSelection() { + func setup() { - return cuckoo_manager.call("didCompletionAccountSelection()", + return cuckoo_manager.call("setup()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didCompletionAccountSelection()) + defaultCall: __defaultImplStub!.setup()) } - public func applyLocalization() { + func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", + parameters: (amount, bonusService), + escapingParameters: (amount, bonusService), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.estimateFee(for: amount, bonusService: bonusService)) } - struct __StubbingProxy_StakingRewardDestSetupViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -49903,44 +48777,19 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") - } - - - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") - } - - - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") - } - - - func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) - } - - func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChangeRewardDestinationViewModel?)> where M1.OptionalMatchedType == ChangeRewardDestinationViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ChangeRewardDestinationViewModel?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupViewProtocol.self, method: "didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?)", parameterMatchers: matchers)) - } - - func didCompletionAccountSelection() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupViewProtocol.self, method: "didCompletionAccountSelection()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt, CrowdloanBonusServiceProtocol?)> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorInputProtocol.self, method: "estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDestSetupViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -49952,228 +48801,235 @@ import SoraFoundation } - - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.__DoNotUse<(ChangeRewardDestinationViewModel?), Void> where M1.OptionalMatchedType == ChangeRewardDestinationViewModel { - let matchers: [Cuckoo.ParameterMatcher<(ChangeRewardDestinationViewModel?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didCompletionAccountSelection() -> Cuckoo.__DoNotUse<(), Void> { + func setup() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("didCompletionAccountSelection()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.__DoNotUse<(BigUInt, CrowdloanBonusServiceProtocol?), Void> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] + return cuckoo_manager.verify("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDestSetupViewProtocolStub: StakingRewardDestSetupViewProtocol { - + class CrowdloanContributionInteractorInputProtocolStub: CrowdloanContributionInteractorInputProtocol { + - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + + + + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - + + func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - +} + + + + class MockCrowdloanContributionInteractorOutputProtocol: CrowdloanContributionInteractorOutputProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = CrowdloanContributionInteractorOutputProtocol - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - + typealias Stubbing = __StubbingProxy_CrowdloanContributionInteractorOutputProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionInteractorOutputProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: CrowdloanContributionInteractorOutputProtocol? + + func enableDefaultImplementation(_ stub: CrowdloanContributionInteractorOutputProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + - func didReceiveFee(viewModel: LocalizableResource?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + + func didReceiveCrowdloan(result: Result) { + + return cuckoo_manager.call("didReceiveCrowdloan(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveCrowdloan(result: result)) + } - func didReceiveRewardDestination(viewModel: ChangeRewardDestinationViewModel?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func didReceiveDisplayInfo(result: Result) { + + return cuckoo_manager.call("didReceiveDisplayInfo(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveDisplayInfo(result: result)) + } - func didCompletionAccountSelection() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func didReceiveAccountInfo(result: Result) { + + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + } - public func applyLocalization() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func didReceiveBlockNumber(result: Result) { + + return cuckoo_manager.call("didReceiveBlockNumber(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveBlockNumber(result: result)) + } -} - - - - class MockStakingRewardDestSetupPresenterProtocol: StakingRewardDestSetupPresenterProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRewardDestSetupPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDestSetupPresenterProtocol - typealias Verification = __VerificationProxy_StakingRewardDestSetupPresenterProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: StakingRewardDestSetupPresenterProtocol? - - func enableDefaultImplementation(_ stub: StakingRewardDestSetupPresenterProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func didReceiveBlockDuration(result: Result) { + + return cuckoo_manager.call("didReceiveBlockDuration(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveBlockDuration(result: result)) + } - - - - - - - func setup() { + func didReceiveLeasingPeriod(result: Result) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveLeasingPeriod(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(result: result)) } - func selectRestakeDestination() { + func didReceiveLeasingOffset(result: Result) { - return cuckoo_manager.call("selectRestakeDestination()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveLeasingOffset(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectRestakeDestination()) + defaultCall: __defaultImplStub!.didReceiveLeasingOffset(result: result)) } - func selectPayoutDestination() { + func didReceiveMinimumBalance(result: Result) { - return cuckoo_manager.call("selectPayoutDestination()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveMinimumBalance(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectPayoutDestination()) + defaultCall: __defaultImplStub!.didReceiveMinimumBalance(result: result)) } - func selectPayoutAccount() { + func didReceiveMinimumContribution(result: Result) { - return cuckoo_manager.call("selectPayoutAccount()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveMinimumContribution(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectPayoutAccount()) + defaultCall: __defaultImplStub!.didReceiveMinimumContribution(result: result)) } - func displayLearnMore() { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("displayLearnMore()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.displayLearnMore()) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - func proceed() { + func didReceiveFee(result: Result) { - return cuckoo_manager.call("proceed()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - struct __StubbingProxy_StakingRewardDestSetupPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -50181,39 +49037,64 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + func didReceiveCrowdloan(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveCrowdloan(result: Result)", parameterMatchers: matchers)) } - func selectRestakeDestination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "selectRestakeDestination()", parameterMatchers: matchers)) + func didReceiveDisplayInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveDisplayInfo(result: Result)", parameterMatchers: matchers)) } - func selectPayoutDestination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "selectPayoutDestination()", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - func selectPayoutAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "selectPayoutAccount()", parameterMatchers: matchers)) + func didReceiveBlockNumber(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveBlockNumber(result: Result)", parameterMatchers: matchers)) } - func displayLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "displayLearnMore()", parameterMatchers: matchers)) + func didReceiveBlockDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveBlockDuration(result: Result)", parameterMatchers: matchers)) } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + func didReceiveLeasingPeriod(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveLeasingOffset(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveMinimumBalance(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveMinimumBalance(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveMinimumContribution(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveMinimumContribution(result: Result)", parameterMatchers: matchers)) + } + + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDestSetupPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -50228,45 +49109,75 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveCrowdloan(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveCrowdloan(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectRestakeDestination() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectRestakeDestination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveDisplayInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveDisplayInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectPayoutDestination() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectPayoutDestination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectPayoutAccount() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectPayoutAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBlockNumber(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBlockNumber(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func displayLearnMore() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("displayLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBlockDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBlockDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveLeasingPeriod(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingPeriod(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveLeasingOffset(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingOffset(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveMinimumBalance(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMinimumBalance(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveMinimumContribution(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMinimumContribution(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDestSetupPresenterProtocolStub: StakingRewardDestSetupPresenterProtocol { + class CrowdloanContributionInteractorOutputProtocolStub: CrowdloanContributionInteractorOutputProtocol { @@ -50274,406 +49185,320 @@ import SoraFoundation - func setup() { + func didReceiveCrowdloan(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectRestakeDestination() { + func didReceiveDisplayInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectPayoutDestination() { + func didReceiveAccountInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectPayoutAccount() { + func didReceiveBlockNumber(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func displayLearnMore() { + func didReceiveBlockDuration(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func proceed() { + func didReceiveLeasingPeriod(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - - - class MockStakingRewardDestSetupInteractorInputProtocol: StakingRewardDestSetupInteractorInputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRewardDestSetupInteractorInputProtocol - - typealias Stubbing = __StubbingProxy_StakingRewardDestSetupInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingRewardDestSetupInteractorInputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: StakingRewardDestSetupInteractorInputProtocol? - - func enableDefaultImplementation(_ stub: StakingRewardDestSetupInteractorInputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - - - - - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) - - } - - func estimateFee() { - - return cuckoo_manager.call("estimateFee()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.estimateFee()) - + func didReceiveLeasingOffset(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func fetchPayoutAccounts() { - - return cuckoo_manager.call("fetchPayoutAccounts()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.fetchPayoutAccounts()) - + func didReceiveMinimumBalance(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - struct __StubbingProxy_StakingRewardDestSetupInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) - } - - func fetchPayoutAccounts() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorInputProtocol.self, method: "fetchPayoutAccounts()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_StakingRewardDestSetupInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func fetchPayoutAccounts() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("fetchPayoutAccounts()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class StakingRewardDestSetupInteractorInputProtocolStub: StakingRewardDestSetupInteractorInputProtocol { - - - - - - func setup() { + func didReceiveMinimumContribution(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func estimateFee() { + func didReceivePriceData(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func fetchPayoutAccounts() { + func didReceiveFee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet + +import BigInt +import SoraFoundation - class MockStakingRewardDestSetupInteractorOutputProtocol: StakingRewardDestSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { + + class MockCrowdloanContributionConfirmViewProtocol: CrowdloanContributionConfirmViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDestSetupInteractorOutputProtocol + typealias MocksType = CrowdloanContributionConfirmViewProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDestSetupInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingRewardDestSetupInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmViewProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionConfirmViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDestSetupInteractorOutputProtocol? + private var __defaultImplStub: CrowdloanContributionConfirmViewProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDestSetupInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } - func didReceiveFee(result: Result) { - - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } - func didReceivePriceData(result: Result) { + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } } - func didReceiveStashItem(result: Result) { - - return cuckoo_manager.call("didReceiveStashItem(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) + var loadableContentView: UIView! { + get { + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) + } } - func didReceiveController(result: Result) { + var shouldDisableInteractionWhenLoading: Bool { + get { + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) + } - return cuckoo_manager.call("didReceiveController(result: Result)", - parameters: (result), - escapingParameters: (result), + } + + + + + + + + func didReceiveAsset(viewModel: AssetBalanceViewModelProtocol) { + + return cuckoo_manager.call("didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveController(result: result)) + defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) } - func didReceiveStash(result: Result) { + func didReceiveFee(viewModel: BalanceViewModelProtocol?) { - return cuckoo_manager.call("didReceiveStash(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveFee(viewModel: BalanceViewModelProtocol?)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStash(result: result)) + defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) } - func didReceiveStakingLedger(result: Result) { + func didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel) { - return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) + defaultCall: __defaultImplStub!.didReceiveCrowdloan(viewModel: viewModel)) } - func didReceiveRewardDestinationAccount(result: Result?, Error>) { + func didReceiveEstimatedReward(viewModel: String?) { - return cuckoo_manager.call("didReceiveRewardDestinationAccount(result: Result?, Error>)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveEstimatedReward(viewModel: String?)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveRewardDestinationAccount(result: result)) + defaultCall: __defaultImplStub!.didReceiveEstimatedReward(viewModel: viewModel)) } - func didReceiveRewardDestinationAddress(result: Result?, Error>) { + func didReceiveBonus(viewModel: String?) { - return cuckoo_manager.call("didReceiveRewardDestinationAddress(result: Result?, Error>)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveBonus(viewModel: String?)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveRewardDestinationAddress(result: result)) + defaultCall: __defaultImplStub!.didReceiveBonus(viewModel: viewModel)) } - func didReceiveCalculator(result: Result) { + func didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM) { - return cuckoo_manager.call("didReceiveCalculator(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveCalculator(result: result)) + defaultCall: __defaultImplStub!.didReceiveRewardDestination(viewModel: viewModel)) } - func didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>) { + public func applyLocalization() { - return cuckoo_manager.call("didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("applyLocalization()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccounts(result: result)) + defaultCall: __defaultImplStub!.applyLocalization()) } - func didReceiveNomination(result: Result) { + func didStartLoading() { - return cuckoo_manager.call("didReceiveNomination(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didStartLoading()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveNomination(result: result)) + defaultCall: __defaultImplStub!.didStartLoading()) } - func didReceiveAccountInfo(result: Result) { + func didStopLoading() { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didStopLoading()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.didStopLoading()) } - struct __StubbingProxy_StakingRewardDestSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionConfirmViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -50681,69 +49506,79 @@ import SoraFoundation } - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager") } - func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) + + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") } - func didReceiveStash(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveStash(result: Result)", parameterMatchers: matchers)) + + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") } - func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) + + func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AssetBalanceViewModelProtocol)> where M1.MatchedType == AssetBalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AssetBalanceViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", parameterMatchers: matchers)) } - func didReceiveRewardDestinationAccount(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result?, Error>)> where M1.MatchedType == Result?, Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result?, Error>)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveRewardDestinationAccount(result: Result?, Error>)", parameterMatchers: matchers)) + func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BalanceViewModelProtocol?)> where M1.OptionalMatchedType == BalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveFee(viewModel: BalanceViewModelProtocol?)", parameterMatchers: matchers)) } - func didReceiveRewardDestinationAddress(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result?, Error>)> where M1.MatchedType == Result?, Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result?, Error>)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveRewardDestinationAddress(result: Result?, Error>)", parameterMatchers: matchers)) + func didReceiveCrowdloan(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributeConfirmViewModel)> where M1.MatchedType == CrowdloanContributeConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributeConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel)", parameterMatchers: matchers)) } - func didReceiveCalculator(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveCalculator(result: Result)", parameterMatchers: matchers)) + func didReceiveEstimatedReward(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveEstimatedReward(viewModel: String?)", parameterMatchers: matchers)) } - func didReceiveAccounts(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[MetaChainAccountResponse], Error>)> where M1.MatchedType == Result<[MetaChainAccountResponse], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[MetaChainAccountResponse], Error>)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", parameterMatchers: matchers)) + func didReceiveBonus(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveBonus(viewModel: String?)", parameterMatchers: matchers)) } - func didReceiveNomination(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveNomination(result: Result)", parameterMatchers: matchers)) + func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanRewardDestinationVM)> where M1.MatchedType == CrowdloanRewardDestinationVM { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanRewardDestinationVM)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", parameterMatchers: matchers)) } - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) + func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + } + + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + } + + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDestSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionConfirmViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -50755,84 +49590,138 @@ import SoraFoundation } - - @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + var isSetup: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var controller: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - @discardableResult - func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + + var localizationManager: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + @discardableResult - func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(AssetBalanceViewModelProtocol), Void> where M1.MatchedType == AssetBalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AssetBalanceViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStash(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStash(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(BalanceViewModelProtocol?), Void> where M1.OptionalMatchedType == BalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveFee(viewModel: BalanceViewModelProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveCrowdloan(viewModel: M1) -> Cuckoo.__DoNotUse<(CrowdloanContributeConfirmViewModel), Void> where M1.MatchedType == CrowdloanContributeConfirmViewModel { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributeConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveRewardDestinationAccount(result: M1) -> Cuckoo.__DoNotUse<(Result?, Error>), Void> where M1.MatchedType == Result?, Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result?, Error>)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveRewardDestinationAccount(result: Result?, Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveEstimatedReward(viewModel: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveEstimatedReward(viewModel: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveRewardDestinationAddress(result: M1) -> Cuckoo.__DoNotUse<(Result?, Error>), Void> where M1.MatchedType == Result?, Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result?, Error>)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveRewardDestinationAddress(result: Result?, Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBonus(viewModel: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveBonus(viewModel: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveCalculator(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveCalculator(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.__DoNotUse<(CrowdloanRewardDestinationVM), Void> where M1.MatchedType == CrowdloanRewardDestinationVM { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanRewardDestinationVM)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveAccounts(result: M1) -> Cuckoo.__DoNotUse<(Result<[MetaChainAccountResponse], Error>), Void> where M1.MatchedType == Result<[MetaChainAccountResponse], Error> { - let matchers: [Cuckoo.ParameterMatcher<(Result<[MetaChainAccountResponse], Error>)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveNomination(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveNomination(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDestSetupInteractorOutputProtocolStub: StakingRewardDestSetupInteractorOutputProtocol { + class CrowdloanContributionConfirmViewProtocolStub: CrowdloanContributionConfirmViewProtocol { + + + + var isSetup: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } + + + + var controller: UIViewController { + get { + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + } + + } + + + + public var localizationManager: LocalizationManagerProtocol? { + get { + return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + } + + set { } + + } + + + + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } @@ -50840,73 +49729,244 @@ import SoraFoundation - func didReceiveFee(result: Result) { + func didReceiveAsset(viewModel: AssetBalanceViewModelProtocol) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceivePriceData(result: Result) { + func didReceiveFee(viewModel: BalanceViewModelProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStashItem(result: Result) { + func didReceiveCrowdloan(viewModel: CrowdloanContributeConfirmViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveController(result: Result) { + func didReceiveEstimatedReward(viewModel: String?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStash(result: Result) { + func didReceiveBonus(viewModel: String?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStakingLedger(result: Result) { + func didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveRewardDestinationAccount(result: Result?, Error>) { + public func applyLocalization() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveRewardDestinationAddress(result: Result?, Error>) { + func didStartLoading() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveCalculator(result: Result) { + func didStopLoading() { return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockCrowdloanContributionConfirmPresenterProtocol: CrowdloanContributionConfirmPresenterProtocol, Cuckoo.ProtocolMock { + typealias MocksType = CrowdloanContributionConfirmPresenterProtocol - func didReceiveAccounts(result: Result<[MetaChainAccountResponse], Error>) { + typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmPresenterProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionConfirmPresenterProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + + + private var __defaultImplStub: CrowdloanContributionConfirmPresenterProtocol? + + func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmPresenterProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() + } + + + + + + + + + + func setup() { + + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.setup()) + + } + + + + func confirm() { + + return cuckoo_manager.call("confirm()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.confirm()) + + } + + + + func presentAccountOptions() { + + return cuckoo_manager.call("presentAccountOptions()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentAccountOptions()) + + } + + + + func presentRewardDestination() { + + return cuckoo_manager.call("presentRewardDestination()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentRewardDestination()) + + } + + + struct __StubbingProxy_CrowdloanContributionConfirmPresenterProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + } + + func presentAccountOptions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmPresenterProtocol.self, method: "presentAccountOptions()", parameterMatchers: matchers)) + } + + func presentRewardDestination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmPresenterProtocol.self, method: "presentRewardDestination()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_CrowdloanContributionConfirmPresenterProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func confirm() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentAccountOptions() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentAccountOptions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentRewardDestination() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentRewardDestination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class CrowdloanContributionConfirmPresenterProtocolStub: CrowdloanContributionConfirmPresenterProtocol { + + + + + + + + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveNomination(result: Result) { + func confirm() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveAccountInfo(result: Result) { + func presentAccountOptions() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentRewardDestination() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -50914,19 +49974,19 @@ import SoraFoundation - class MockStakingRewardDestSetupWireframeProtocol: StakingRewardDestSetupWireframeProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanContributionConfirmInteractorInputProtocol: CrowdloanContributionConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDestSetupWireframeProtocol + typealias MocksType = CrowdloanContributionConfirmInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDestSetupWireframeProtocol - typealias Verification = __VerificationProxy_StakingRewardDestSetupWireframeProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmInteractorInputProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionConfirmInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDestSetupWireframeProtocol? + private var __defaultImplStub: CrowdloanContributionConfirmInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDestSetupWireframeProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -50939,81 +49999,66 @@ import SoraFoundation - func proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination) { - - return cuckoo_manager.call("proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination)", - parameters: (view, rewardDestination), - escapingParameters: (view, rewardDestination), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.proceed(view: view, rewardDestination: rewardDestination)) - - } - - - - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func estimateFee(for contribution: BigUInt) { - return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", - parameters: (url, view, style), - escapingParameters: (url, view, style), + return cuckoo_manager.call("estimateFee(for: BigUInt)", + parameters: (contribution), + escapingParameters: (contribution), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) + defaultCall: __defaultImplStub!.estimateFee(for: contribution)) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func submit(contribution: BigUInt) { - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), + return cuckoo_manager.call("submit(contribution: BigUInt)", + parameters: (contribution), + escapingParameters: (contribution), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + defaultCall: __defaultImplStub!.submit(contribution: contribution)) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func setup() { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("setup()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.setup()) } - func presentAccountSelection(_ accounts: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from view: ControllerBackedProtocol?, context: AnyObject?) { + func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { - return cuckoo_manager.call("presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", - parameters: (accounts, selectedAccountItem, title, delegate, view, context), - escapingParameters: (accounts, selectedAccountItem, title, delegate, view, context), + return cuckoo_manager.call("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", + parameters: (amount, bonusService), + escapingParameters: (amount, bonusService), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.presentAccountSelection(accounts, selectedAccountItem: selectedAccountItem, title: title, delegate: delegate, from: view, context: context)) + defaultCall: __defaultImplStub!.estimateFee(for: amount, bonusService: bonusService)) } - struct __StubbingProxy_StakingRewardDestSetupWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -51021,34 +50066,29 @@ import SoraFoundation } - func proceed(view: M1, rewardDestination: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRewardDestSetupViewProtocol?, RewardDestination)> where M1.OptionalMatchedType == StakingRewardDestSetupViewProtocol, M2.MatchedType == RewardDestination { - let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestSetupViewProtocol?, RewardDestination)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: rewardDestination) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination)", parameterMatchers: matchers)) - } - - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) + func estimateFee(for contribution: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt)> where M1.MatchedType == BigUInt { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt)>] = [wrap(matchable: contribution) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorInputProtocol.self, method: "estimateFee(for: BigUInt)", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func submit(contribution: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt)> where M1.MatchedType == BigUInt { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt)>] = [wrap(matchable: contribution) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorInputProtocol.self, method: "submit(contribution: BigUInt)", parameterMatchers: matchers)) } - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func presentAccountSelection(_ accounts: M1, selectedAccountItem: M2, title: M3, delegate: M4, from view: M5, context: M6) -> Cuckoo.ProtocolStubNoReturnFunction<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)> where M1.MatchedType == [MetaChainAccountResponse], M2.OptionalMatchedType == MetaChainAccountResponse, M3.MatchedType == LocalizableResource, M4.MatchedType == ModalPickerViewControllerDelegate, M5.OptionalMatchedType == ControllerBackedProtocol, M6.OptionalMatchedType == AnyObject { - let matchers: [Cuckoo.ParameterMatcher<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)>] = [wrap(matchable: accounts) { $0.0 }, wrap(matchable: selectedAccountItem) { $0.1 }, wrap(matchable: title) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: view) { $0.4 }, wrap(matchable: context) { $0.5 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDestSetupWireframeProtocol.self, method: "presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", parameterMatchers: matchers)) + func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt, CrowdloanBonusServiceProtocol?)> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorInputProtocol.self, method: "estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDestSetupWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -51063,39 +50103,33 @@ import SoraFoundation @discardableResult - func proceed(view: M1, rewardDestination: M2) -> Cuckoo.__DoNotUse<(StakingRewardDestSetupViewProtocol?, RewardDestination), Void> where M1.OptionalMatchedType == StakingRewardDestSetupViewProtocol, M2.MatchedType == RewardDestination { - let matchers: [Cuckoo.ParameterMatcher<(StakingRewardDestSetupViewProtocol?, RewardDestination)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: rewardDestination) { $0.1 }] - return cuckoo_manager.verify("proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { - let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] - return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee(for contribution: M1) -> Cuckoo.__DoNotUse<(BigUInt), Void> where M1.MatchedType == BigUInt { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt)>] = [wrap(matchable: contribution) { $0 }] + return cuckoo_manager.verify("estimateFee(for: BigUInt)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func submit(contribution: M1) -> Cuckoo.__DoNotUse<(BigUInt), Void> where M1.MatchedType == BigUInt { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt)>] = [wrap(matchable: contribution) { $0 }] + return cuckoo_manager.verify("submit(contribution: BigUInt)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func presentAccountSelection(_ accounts: M1, selectedAccountItem: M2, title: M3, delegate: M4, from view: M5, context: M6) -> Cuckoo.__DoNotUse<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?), Void> where M1.MatchedType == [MetaChainAccountResponse], M2.OptionalMatchedType == MetaChainAccountResponse, M3.MatchedType == LocalizableResource, M4.MatchedType == ModalPickerViewControllerDelegate, M5.OptionalMatchedType == ControllerBackedProtocol, M6.OptionalMatchedType == AnyObject { - let matchers: [Cuckoo.ParameterMatcher<([MetaChainAccountResponse], MetaChainAccountResponse?, LocalizableResource, ModalPickerViewControllerDelegate, ControllerBackedProtocol?, AnyObject?)>] = [wrap(matchable: accounts) { $0.0 }, wrap(matchable: selectedAccountItem) { $0.1 }, wrap(matchable: title) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: view) { $0.4 }, wrap(matchable: context) { $0.5 }] - return cuckoo_manager.verify("presentAccountSelection(_: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from: ControllerBackedProtocol?, context: AnyObject?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.__DoNotUse<(BigUInt, CrowdloanBonusServiceProtocol?), Void> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] + return cuckoo_manager.verify("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDestSetupWireframeProtocolStub: StakingRewardDestSetupWireframeProtocol { + class CrowdloanContributionConfirmInteractorInputProtocolStub: CrowdloanContributionConfirmInteractorInputProtocol { @@ -51103,156 +50137,267 @@ import SoraFoundation - func proceed(view: StakingRewardDestSetupViewProtocol?, rewardDestination: RewardDestination) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + func estimateFee(for contribution: BigUInt) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func submit(contribution: BigUInt) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func presentAccountSelection(_ accounts: [MetaChainAccountResponse], selectedAccountItem: MetaChainAccountResponse?, title: LocalizableResource, delegate: ModalPickerViewControllerDelegate, from view: ControllerBackedProtocol?, context: AnyObject?) { + func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } -import Cuckoo -@testable import novawallet - -import SoraFoundation - - class MockStakingRewardDetailsViewProtocol: StakingRewardDetailsViewProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanContributionConfirmInteractorOutputProtocol: CrowdloanContributionConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDetailsViewProtocol + typealias MocksType = CrowdloanContributionConfirmInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDetailsViewProtocol - typealias Verification = __VerificationProxy_StakingRewardDetailsViewProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmInteractorOutputProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionConfirmInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDetailsViewProtocol? + private var __defaultImplStub: CrowdloanContributionConfirmInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDetailsViewProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } + + - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } + + + func didSubmitContribution(result: Result) { + + return cuckoo_manager.call("didSubmitContribution(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didSubmitContribution(result: result)) } - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } + func didReceiveDisplayAddress(result: Result) { + + return cuckoo_manager.call("didReceiveDisplayAddress(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveDisplayAddress(result: result)) } - - + + func didReceiveRewardDestinationAddress(_ address: AccountAddress) { + + return cuckoo_manager.call("didReceiveRewardDestinationAddress(_: AccountAddress)", + parameters: (address), + escapingParameters: (address), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveRewardDestinationAddress(address)) + + } - func didReceive(amountViewModel: BalanceViewModelProtocol) { + func didReceiveCrowdloan(result: Result) { - return cuckoo_manager.call("didReceive(amountViewModel: BalanceViewModelProtocol)", - parameters: (amountViewModel), - escapingParameters: (amountViewModel), + return cuckoo_manager.call("didReceiveCrowdloan(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(amountViewModel: amountViewModel)) + defaultCall: __defaultImplStub!.didReceiveCrowdloan(result: result)) } - func didReceive(validatorViewModel: StackCellViewModel) { + func didReceiveDisplayInfo(result: Result) { - return cuckoo_manager.call("didReceive(validatorViewModel: StackCellViewModel)", - parameters: (validatorViewModel), - escapingParameters: (validatorViewModel), + return cuckoo_manager.call("didReceiveDisplayInfo(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(validatorViewModel: validatorViewModel)) + defaultCall: __defaultImplStub!.didReceiveDisplayInfo(result: result)) } - func didReceive(eraViewModel: StackCellViewModel) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("didReceive(eraViewModel: StackCellViewModel)", - parameters: (eraViewModel), - escapingParameters: (eraViewModel), + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(eraViewModel: eraViewModel)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - func didReceive(remainedTime: NSAttributedString) { + func didReceiveBlockNumber(result: Result) { - return cuckoo_manager.call("didReceive(remainedTime: NSAttributedString)", - parameters: (remainedTime), - escapingParameters: (remainedTime), + return cuckoo_manager.call("didReceiveBlockNumber(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(remainedTime: remainedTime)) + defaultCall: __defaultImplStub!.didReceiveBlockNumber(result: result)) + + } + + + + func didReceiveBlockDuration(result: Result) { + + return cuckoo_manager.call("didReceiveBlockDuration(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveBlockDuration(result: result)) + + } + + + + func didReceiveLeasingPeriod(result: Result) { + + return cuckoo_manager.call("didReceiveLeasingPeriod(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(result: result)) + + } + + + + func didReceiveLeasingOffset(result: Result) { + + return cuckoo_manager.call("didReceiveLeasingOffset(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveLeasingOffset(result: result)) + + } + + + + func didReceiveMinimumBalance(result: Result) { + + return cuckoo_manager.call("didReceiveMinimumBalance(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveMinimumBalance(result: result)) + + } + + + + func didReceiveMinimumContribution(result: Result) { + + return cuckoo_manager.call("didReceiveMinimumContribution(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveMinimumContribution(result: result)) + + } + + + + func didReceivePriceData(result: Result) { + + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + + } + + + + func didReceiveFee(result: Result) { + + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - struct __StubbingProxy_StakingRewardDetailsViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -51260,39 +50405,79 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") + func didSubmitContribution(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didSubmitContribution(result: Result)", parameterMatchers: matchers)) } + func didReceiveDisplayAddress(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveDisplayAddress(result: Result)", parameterMatchers: matchers)) + } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") + func didReceiveRewardDestinationAddress(_ address: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AccountAddress)> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: address) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveRewardDestinationAddress(_: AccountAddress)", parameterMatchers: matchers)) } + func didReceiveCrowdloan(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveCrowdloan(result: Result)", parameterMatchers: matchers)) + } - func didReceive(amountViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BalanceViewModelProtocol)> where M1.MatchedType == BalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol)>] = [wrap(matchable: amountViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsViewProtocol.self, method: "didReceive(amountViewModel: BalanceViewModelProtocol)", parameterMatchers: matchers)) + func didReceiveDisplayInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveDisplayInfo(result: Result)", parameterMatchers: matchers)) } - func didReceive(validatorViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StackCellViewModel)> where M1.MatchedType == StackCellViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StackCellViewModel)>] = [wrap(matchable: validatorViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsViewProtocol.self, method: "didReceive(validatorViewModel: StackCellViewModel)", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - func didReceive(eraViewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StackCellViewModel)> where M1.MatchedType == StackCellViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StackCellViewModel)>] = [wrap(matchable: eraViewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsViewProtocol.self, method: "didReceive(eraViewModel: StackCellViewModel)", parameterMatchers: matchers)) + func didReceiveBlockNumber(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveBlockNumber(result: Result)", parameterMatchers: matchers)) } - func didReceive(remainedTime: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(NSAttributedString)> where M1.MatchedType == NSAttributedString { - let matchers: [Cuckoo.ParameterMatcher<(NSAttributedString)>] = [wrap(matchable: remainedTime) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsViewProtocol.self, method: "didReceive(remainedTime: NSAttributedString)", parameterMatchers: matchers)) + func didReceiveBlockDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveBlockDuration(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveLeasingPeriod(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveLeasingOffset(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveMinimumBalance(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveMinimumBalance(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveMinimumContribution(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveMinimumContribution(result: Result)", parameterMatchers: matchers)) + } + + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDetailsViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -51304,90 +50489,182 @@ import SoraFoundation } + - var isSetup: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didSubmitContribution(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didSubmitContribution(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didReceiveDisplayAddress(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveDisplayAddress(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } - var controller: Cuckoo.VerifyReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) + @discardableResult + func didReceiveRewardDestinationAddress(_ address: M1) -> Cuckoo.__DoNotUse<(AccountAddress), Void> where M1.MatchedType == AccountAddress { + let matchers: [Cuckoo.ParameterMatcher<(AccountAddress)>] = [wrap(matchable: address) { $0 }] + return cuckoo_manager.verify("didReceiveRewardDestinationAddress(_: AccountAddress)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - + @discardableResult + func didReceiveCrowdloan(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveCrowdloan(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } @discardableResult - func didReceive(amountViewModel: M1) -> Cuckoo.__DoNotUse<(BalanceViewModelProtocol), Void> where M1.MatchedType == BalanceViewModelProtocol { - let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol)>] = [wrap(matchable: amountViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(amountViewModel: BalanceViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveDisplayInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveDisplayInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(validatorViewModel: M1) -> Cuckoo.__DoNotUse<(StackCellViewModel), Void> where M1.MatchedType == StackCellViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StackCellViewModel)>] = [wrap(matchable: validatorViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(validatorViewModel: StackCellViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(eraViewModel: M1) -> Cuckoo.__DoNotUse<(StackCellViewModel), Void> where M1.MatchedType == StackCellViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StackCellViewModel)>] = [wrap(matchable: eraViewModel) { $0 }] - return cuckoo_manager.verify("didReceive(eraViewModel: StackCellViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBlockNumber(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBlockNumber(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceive(remainedTime: M1) -> Cuckoo.__DoNotUse<(NSAttributedString), Void> where M1.MatchedType == NSAttributedString { - let matchers: [Cuckoo.ParameterMatcher<(NSAttributedString)>] = [wrap(matchable: remainedTime) { $0 }] - return cuckoo_manager.verify("didReceive(remainedTime: NSAttributedString)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBlockDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBlockDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveLeasingPeriod(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingPeriod(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveLeasingOffset(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingOffset(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveMinimumBalance(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMinimumBalance(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveMinimumContribution(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMinimumContribution(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDetailsViewProtocolStub: StakingRewardDetailsViewProtocol { - + class CrowdloanContributionConfirmInteractorOutputProtocolStub: CrowdloanContributionConfirmInteractorOutputProtocol { + - var isSetup: Bool { - get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) - } - + + + + + func didSubmitContribution(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - var controller: UIViewController { - get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) - } - + + func didReceiveDisplayAddress(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - - + + func didReceiveRewardDestinationAddress(_ address: AccountAddress) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } - func didReceive(amountViewModel: BalanceViewModelProtocol) { + func didReceiveCrowdloan(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(validatorViewModel: StackCellViewModel) { + func didReceiveDisplayInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(eraViewModel: StackCellViewModel) { + func didReceiveAccountInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceive(remainedTime: NSAttributedString) { + func didReceiveBlockNumber(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveBlockDuration(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveLeasingPeriod(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveLeasingOffset(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveMinimumBalance(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveMinimumContribution(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceivePriceData(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveFee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -51395,19 +50672,19 @@ import SoraFoundation - class MockStakingRewardDetailsPresenterProtocol: StakingRewardDetailsPresenterProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanContributionConfirmWireframeProtocol: CrowdloanContributionConfirmWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDetailsPresenterProtocol + typealias MocksType = CrowdloanContributionConfirmWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDetailsPresenterProtocol - typealias Verification = __VerificationProxy_StakingRewardDetailsPresenterProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionConfirmWireframeProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionConfirmWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDetailsPresenterProtocol? + private var __defaultImplStub: CrowdloanContributionConfirmWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDetailsPresenterProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionConfirmWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -51420,51 +50697,51 @@ import SoraFoundation - func setup() { + func complete(on view: CrowdloanContributionConfirmViewProtocol?) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("complete(on: CrowdloanContributionConfirmViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.complete(on: view)) } - func handlePayoutAction() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("handlePayoutAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.handlePayoutAction()) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - func handleValidatorAccountAction() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("handleValidatorAccountAction()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.handleValidatorAccountAction()) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } - struct __StubbingProxy_StakingRewardDetailsPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionConfirmWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -51472,24 +50749,24 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + func complete(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributionConfirmViewProtocol?)> where M1.OptionalMatchedType == CrowdloanContributionConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmWireframeProtocol.self, method: "complete(on: CrowdloanContributionConfirmViewProtocol?)", parameterMatchers: matchers)) } - func handlePayoutAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsPresenterProtocol.self, method: "handlePayoutAction()", parameterMatchers: matchers)) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func handleValidatorAccountAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsPresenterProtocol.self, method: "handleValidatorAccountAction()", parameterMatchers: matchers)) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardDetailsPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionConfirmWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -51504,27 +50781,27 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func complete(on view: M1) -> Cuckoo.__DoNotUse<(CrowdloanContributionConfirmViewProtocol?), Void> where M1.OptionalMatchedType == CrowdloanContributionConfirmViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("complete(on: CrowdloanContributionConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func handlePayoutAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handlePayoutAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func handleValidatorAccountAction() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handleValidatorAccountAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardDetailsPresenterProtocolStub: StakingRewardDetailsPresenterProtocol { + class CrowdloanContributionConfirmWireframeProtocolStub: CrowdloanContributionConfirmWireframeProtocol { @@ -51532,398 +50809,239 @@ import SoraFoundation - func setup() { + func complete(on view: CrowdloanContributionConfirmViewProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func handlePayoutAction() { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func handleValidatorAccountAction() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } } +import Cuckoo +@testable import novawallet + +import BigInt +import CommonWallet +import Foundation +import SoraFoundation + - class MockStakingRewardDetailsInteractorInputProtocol: StakingRewardDetailsInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanContributionSetupViewProtocol: CrowdloanContributionSetupViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardDetailsInteractorInputProtocol + typealias MocksType = CrowdloanContributionSetupViewProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDetailsInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingRewardDetailsInteractorInputProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupViewProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionSetupViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardDetailsInteractorInputProtocol? + private var __defaultImplStub: CrowdloanContributionSetupViewProtocol? - func enableDefaultImplementation(_ stub: StakingRewardDetailsInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionSetupViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - - + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } - func setup() { - - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.setup()) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } - - struct __StubbingProxy_StakingRewardDetailsInteractorInputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_StakingRewardDetailsInteractorInputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class StakingRewardDetailsInteractorInputProtocolStub: StakingRewardDetailsInteractorInputProtocol { - - + public var localizationManager: LocalizationManagerProtocol? { + get { + return cuckoo_manager.getter("localizationManager", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager) + } + + set { + cuckoo_manager.setter("localizationManager", + value: newValue, + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.localizationManager = newValue) + } + + } - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + var loadableContentView: UIView! { + get { + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) + } + } -} - - - - class MockStakingRewardDetailsInteractorOutputProtocol: StakingRewardDetailsInteractorOutputProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRewardDetailsInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingRewardDetailsInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingRewardDetailsInteractorOutputProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: StakingRewardDetailsInteractorOutputProtocol? - - func enableDefaultImplementation(_ stub: StakingRewardDetailsInteractorOutputProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + var shouldDisableInteractionWhenLoading: Bool { + get { + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) + } + } - - - func didReceive(priceResult: Result) { + func didReceiveAsset(viewModel: AssetBalanceViewModelProtocol) { - return cuckoo_manager.call("didReceive(priceResult: Result)", - parameters: (priceResult), - escapingParameters: (priceResult), + return cuckoo_manager.call("didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(priceResult: priceResult)) + defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) } - - struct __StubbingProxy_StakingRewardDetailsInteractorOutputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func didReceive(priceResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsInteractorOutputProtocol.self, method: "didReceive(priceResult: Result)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_StakingRewardDetailsInteractorOutputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func didReceive(priceResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] - return cuckoo_manager.verify("didReceive(priceResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class StakingRewardDetailsInteractorOutputProtocolStub: StakingRewardDetailsInteractorOutputProtocol { - - - - - - - - func didReceive(priceResult: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - - - class MockStakingRewardDetailsWireframeProtocol: StakingRewardDetailsWireframeProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRewardDetailsWireframeProtocol - - typealias Stubbing = __StubbingProxy_StakingRewardDetailsWireframeProtocol - typealias Verification = __VerificationProxy_StakingRewardDetailsWireframeProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: StakingRewardDetailsWireframeProtocol? - - func enableDefaultImplementation(_ stub: StakingRewardDetailsWireframeProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - - - func showPayoutConfirmation(from view: ControllerBackedProtocol?, payoutInfo: PayoutInfo) { + func didReceiveFee(viewModel: BalanceViewModelProtocol?) { - return cuckoo_manager.call("showPayoutConfirmation(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo)", - parameters: (view, payoutInfo), - escapingParameters: (view, payoutInfo), + return cuckoo_manager.call("didReceiveFee(viewModel: BalanceViewModelProtocol?)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showPayoutConfirmation(from: view, payoutInfo: payoutInfo)) + defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) } - - struct __StubbingProxy_StakingRewardDetailsWireframeProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func showPayoutConfirmation(from view: M1, payoutInfo: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, PayoutInfo)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == PayoutInfo { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, PayoutInfo)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: payoutInfo) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardDetailsWireframeProtocol.self, method: "showPayoutConfirmation(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_StakingRewardDetailsWireframeProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func showPayoutConfirmation(from view: M1, payoutInfo: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, PayoutInfo), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == PayoutInfo { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, PayoutInfo)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: payoutInfo) { $0.1 }] - return cuckoo_manager.verify("showPayoutConfirmation(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class StakingRewardDetailsWireframeProtocolStub: StakingRewardDetailsWireframeProtocol { - - - - - - - - func showPayoutConfirmation(from view: ControllerBackedProtocol?, payoutInfo: PayoutInfo) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - -} - - -import Cuckoo -@testable import novawallet - -import SoraFoundation -import SoraUI - - - class MockStakingRewardPayoutsViewProtocol: StakingRewardPayoutsViewProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRewardPayoutsViewProtocol - typealias Stubbing = __StubbingProxy_StakingRewardPayoutsViewProtocol - typealias Verification = __VerificationProxy_StakingRewardPayoutsViewProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: StakingRewardPayoutsViewProtocol? - - func enableDefaultImplementation(_ stub: StakingRewardPayoutsViewProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func didReceiveInput(viewModel: AmountInputViewModelProtocol) { + + return cuckoo_manager.call("didReceiveInput(viewModel: AmountInputViewModelProtocol)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) + } - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } + func didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel) { + + return cuckoo_manager.call("didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveCrowdloan(viewModel: viewModel)) } - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } + func didReceiveEstimatedReward(viewModel: String?) { + + return cuckoo_manager.call("didReceiveEstimatedReward(viewModel: String?)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveEstimatedReward(viewModel: viewModel)) } - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } + func didReceiveBonus(viewModel: String?) { - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } + return cuckoo_manager.call("didReceiveBonus(viewModel: String?)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveBonus(viewModel: viewModel)) } - - - - - func reload(with state: StakingRewardPayoutsViewState) { + func didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM) { - return cuckoo_manager.call("reload(with: StakingRewardPayoutsViewState)", - parameters: (state), - escapingParameters: (state), + return cuckoo_manager.call("didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", + parameters: (viewModel), + escapingParameters: (viewModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload(with: state)) + defaultCall: __defaultImplStub!.didReceiveRewardDestination(viewModel: viewModel)) } @@ -51942,8 +51060,38 @@ import SoraUI } + + + func didStartLoading() { + + return cuckoo_manager.call("didStartLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStartLoading()) + + } + + + + func didStopLoading() { + + return cuckoo_manager.call("didStopLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStopLoading()) + + } + - struct __StubbingProxy_StakingRewardPayoutsViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionSetupViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -51951,34 +51099,84 @@ import SoraUI } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { + var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { return .init(manager: cuckoo_manager, name: "localizationManager") } - func reload(with state: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingRewardPayoutsViewState)> where M1.MatchedType == StakingRewardPayoutsViewState { - let matchers: [Cuckoo.ParameterMatcher<(StakingRewardPayoutsViewState)>] = [wrap(matchable: state) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsViewProtocol.self, method: "reload(with: StakingRewardPayoutsViewState)", parameterMatchers: matchers)) + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") + } + + + func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AssetBalanceViewModelProtocol)> where M1.MatchedType == AssetBalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AssetBalanceViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", parameterMatchers: matchers)) + } + + func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BalanceViewModelProtocol?)> where M1.OptionalMatchedType == BalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveFee(viewModel: BalanceViewModelProtocol?)", parameterMatchers: matchers)) + } + + func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(AmountInputViewModelProtocol)> where M1.MatchedType == AmountInputViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AmountInputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveInput(viewModel: AmountInputViewModelProtocol)", parameterMatchers: matchers)) + } + + func didReceiveCrowdloan(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributionSetupViewModel)> where M1.MatchedType == CrowdloanContributionSetupViewModel { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel)", parameterMatchers: matchers)) + } + + func didReceiveEstimatedReward(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveEstimatedReward(viewModel: String?)", parameterMatchers: matchers)) + } + + func didReceiveBonus(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String?)> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveBonus(viewModel: String?)", parameterMatchers: matchers)) + } + + func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanRewardDestinationVM)> where M1.MatchedType == CrowdloanRewardDestinationVM { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanRewardDestinationVM)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", parameterMatchers: matchers)) } func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + } + + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + } + + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardPayoutsViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionSetupViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -52005,12 +51203,58 @@ import SoraUI return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func reload(with state: M1) -> Cuckoo.__DoNotUse<(StakingRewardPayoutsViewState), Void> where M1.MatchedType == StakingRewardPayoutsViewState { - let matchers: [Cuckoo.ParameterMatcher<(StakingRewardPayoutsViewState)>] = [wrap(matchable: state) { $0 }] - return cuckoo_manager.verify("reload(with: StakingRewardPayoutsViewState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(AssetBalanceViewModelProtocol), Void> where M1.MatchedType == AssetBalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AssetBalanceViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveAsset(viewModel: AssetBalanceViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(BalanceViewModelProtocol?), Void> where M1.OptionalMatchedType == BalanceViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BalanceViewModelProtocol?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveFee(viewModel: BalanceViewModelProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(AmountInputViewModelProtocol), Void> where M1.MatchedType == AmountInputViewModelProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AmountInputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveInput(viewModel: AmountInputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveCrowdloan(viewModel: M1) -> Cuckoo.__DoNotUse<(CrowdloanContributionSetupViewModel), Void> where M1.MatchedType == CrowdloanContributionSetupViewModel { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveEstimatedReward(viewModel: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveEstimatedReward(viewModel: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveBonus(viewModel: M1) -> Cuckoo.__DoNotUse<(String?), Void> where M1.OptionalMatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String?)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveBonus(viewModel: String?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveRewardDestination(viewModel: M1) -> Cuckoo.__DoNotUse<(CrowdloanRewardDestinationVM), Void> where M1.MatchedType == CrowdloanRewardDestinationVM { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanRewardDestinationVM)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -52019,10 +51263,22 @@ import SoraUI return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } - class StakingRewardPayoutsViewProtocolStub: StakingRewardPayoutsViewProtocol { + class CrowdloanContributionSetupViewProtocolStub: CrowdloanContributionSetupViewProtocol { @@ -52052,6 +51308,24 @@ import SoraUI set { } } + + + + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } @@ -52059,7 +51333,43 @@ import SoraUI - func reload(with state: StakingRewardPayoutsViewState) { + func didReceiveAsset(viewModel: AssetBalanceViewModelProtocol) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveFee(viewModel: BalanceViewModelProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveInput(viewModel: AmountInputViewModelProtocol) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveCrowdloan(viewModel: CrowdloanContributionSetupViewModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveEstimatedReward(viewModel: String?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveBonus(viewModel: String?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveRewardDestination(viewModel: CrowdloanRewardDestinationVM) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -52069,23 +51379,35 @@ import SoraUI return DefaultValueRegistry.defaultValue(for: (Void).self) } + + + func didStartLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStopLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + } - class MockStakingRewardPayoutsPresenterProtocol: StakingRewardPayoutsPresenterProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanContributionSetupPresenterProtocol: CrowdloanContributionSetupPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardPayoutsPresenterProtocol + typealias MocksType = CrowdloanContributionSetupPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingRewardPayoutsPresenterProtocol - typealias Verification = __VerificationProxy_StakingRewardPayoutsPresenterProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupPresenterProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionSetupPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardPayoutsPresenterProtocol? + private var __defaultImplStub: CrowdloanContributionSetupPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingRewardPayoutsPresenterProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionSetupPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -52113,66 +51435,96 @@ import SoraUI - func handleSelectedHistory(at index: Int) { + func selectAmountPercentage(_ percentage: Float) { - return cuckoo_manager.call("handleSelectedHistory(at: Int)", - parameters: (index), - escapingParameters: (index), + return cuckoo_manager.call("selectAmountPercentage(_: Float)", + parameters: (percentage), + escapingParameters: (percentage), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.handleSelectedHistory(at: index)) + defaultCall: __defaultImplStub!.selectAmountPercentage(percentage)) } - func handlePayoutAction() { + func updateAmount(_ newValue: Decimal) { - return cuckoo_manager.call("handlePayoutAction()", + return cuckoo_manager.call("updateAmount(_: Decimal)", + parameters: (newValue), + escapingParameters: (newValue), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.updateAmount(newValue)) + + } + + + + func proceed() { + + return cuckoo_manager.call("proceed()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.handlePayoutAction()) + defaultCall: __defaultImplStub!.proceed()) } - func reload() { + func presentLearnMore() { - return cuckoo_manager.call("reload()", + return cuckoo_manager.call("presentLearnMore()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload()) + defaultCall: __defaultImplStub!.presentLearnMore()) } - func getTimeLeftString(at index: Int) -> LocalizableResource? { + func presentAdditionalBonuses() { - return cuckoo_manager.call("getTimeLeftString(at: Int) -> LocalizableResource?", - parameters: (index), - escapingParameters: (index), + return cuckoo_manager.call("presentAdditionalBonuses()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.getTimeLeftString(at: index)) + defaultCall: __defaultImplStub!.presentAdditionalBonuses()) + + } + + + + func presentRewardDestination() { + + return cuckoo_manager.call("presentRewardDestination()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentRewardDestination()) } - struct __StubbingProxy_StakingRewardPayoutsPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionSetupPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -52182,32 +51534,42 @@ import SoraUI func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func handleSelectedHistory(at index: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Int)> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "handleSelectedHistory(at: Int)", parameterMatchers: matchers)) + func selectAmountPercentage(_ percentage: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Float)> where M1.MatchedType == Float { + let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "selectAmountPercentage(_: Float)", parameterMatchers: matchers)) } - func handlePayoutAction() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func updateAmount(_ newValue: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "updateAmount(_: Decimal)", parameterMatchers: matchers)) + } + + func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "handlePayoutAction()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) } - func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func presentLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "reload()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "presentLearnMore()", parameterMatchers: matchers)) } - func getTimeLeftString(at index: M1) -> Cuckoo.ProtocolStubFunction<(Int), LocalizableResource?> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsPresenterProtocol.self, method: "getTimeLeftString(at: Int) -> LocalizableResource?", parameterMatchers: matchers)) + func presentAdditionalBonuses() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "presentAdditionalBonuses()", parameterMatchers: matchers)) + } + + func presentRewardDestination() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupPresenterProtocol.self, method: "presentRewardDestination()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardPayoutsPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionSetupPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -52228,33 +51590,45 @@ import SoraUI } @discardableResult - func handleSelectedHistory(at index: M1) -> Cuckoo.__DoNotUse<(Int), Void> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("handleSelectedHistory(at: Int)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectAmountPercentage(_ percentage: M1) -> Cuckoo.__DoNotUse<(Float), Void> where M1.MatchedType == Float { + let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] + return cuckoo_manager.verify("selectAmountPercentage(_: Float)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func handlePayoutAction() -> Cuckoo.__DoNotUse<(), Void> { + func updateAmount(_ newValue: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { + let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] + return cuckoo_manager.verify("updateAmount(_: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func proceed() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("handlePayoutAction()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func reload() -> Cuckoo.__DoNotUse<(), Void> { + func presentLearnMore() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("presentLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func getTimeLeftString(at index: M1) -> Cuckoo.__DoNotUse<(Int), LocalizableResource?> where M1.MatchedType == Int { - let matchers: [Cuckoo.ParameterMatcher<(Int)>] = [wrap(matchable: index) { $0 }] - return cuckoo_manager.verify("getTimeLeftString(at: Int) -> LocalizableResource?", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentAdditionalBonuses() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentAdditionalBonuses()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentRewardDestination() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentRewardDestination()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardPayoutsPresenterProtocolStub: StakingRewardPayoutsPresenterProtocol { + class CrowdloanContributionSetupPresenterProtocolStub: CrowdloanContributionSetupPresenterProtocol { @@ -52268,45 +51642,57 @@ import SoraUI - func handleSelectedHistory(at index: Int) { + func selectAmountPercentage(_ percentage: Float) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func handlePayoutAction() { + func updateAmount(_ newValue: Decimal) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func reload() { + func proceed() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func getTimeLeftString(at index: Int) -> LocalizableResource? { - return DefaultValueRegistry.defaultValue(for: (LocalizableResource?).self) + func presentLearnMore() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentAdditionalBonuses() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentRewardDestination() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } } - class MockStakingRewardPayoutsInteractorInputProtocol: StakingRewardPayoutsInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanContributionSetupInteractorInputProtocol: CrowdloanContributionSetupInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardPayoutsInteractorInputProtocol + typealias MocksType = CrowdloanContributionSetupInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingRewardPayoutsInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingRewardPayoutsInteractorInputProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupInteractorInputProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionSetupInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardPayoutsInteractorInputProtocol? + private var __defaultImplStub: CrowdloanContributionSetupInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingRewardPayoutsInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionSetupInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -52334,21 +51720,21 @@ import SoraUI - func reload() { + func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { - return cuckoo_manager.call("reload()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", + parameters: (amount, bonusService), + escapingParameters: (amount, bonusService), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.reload()) + defaultCall: __defaultImplStub!.estimateFee(for: amount, bonusService: bonusService)) } - struct __StubbingProxy_StakingRewardPayoutsInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionSetupInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -52358,17 +51744,17 @@ import SoraUI func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - - func reload() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorInputProtocol.self, method: "reload()", parameterMatchers: matchers)) + + func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(BigUInt, CrowdloanBonusServiceProtocol?)> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorInputProtocol.self, method: "estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardPayoutsInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionSetupInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -52389,15 +51775,15 @@ import SoraUI } @discardableResult - func reload() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("reload()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func estimateFee(for amount: M1, bonusService: M2) -> Cuckoo.__DoNotUse<(BigUInt, CrowdloanBonusServiceProtocol?), Void> where M1.MatchedType == BigUInt, M2.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(BigUInt, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: bonusService) { $0.1 }] + return cuckoo_manager.verify("estimateFee(for: BigUInt, bonusService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardPayoutsInteractorInputProtocolStub: StakingRewardPayoutsInteractorInputProtocol { + class CrowdloanContributionSetupInteractorInputProtocolStub: CrowdloanContributionSetupInteractorInputProtocol { @@ -52411,7 +51797,7 @@ import SoraUI - func reload() { + func estimateFee(for amount: BigUInt, bonusService: CrowdloanBonusServiceProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -52419,19 +51805,19 @@ import SoraUI - class MockStakingRewardPayoutsInteractorOutputProtocol: StakingRewardPayoutsInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanContributionSetupInteractorOutputProtocol: CrowdloanContributionSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingRewardPayoutsInteractorOutputProtocol + typealias MocksType = CrowdloanContributionSetupInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingRewardPayoutsInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingRewardPayoutsInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupInteractorOutputProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionSetupInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingRewardPayoutsInteractorOutputProtocol? + private var __defaultImplStub: CrowdloanContributionSetupInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingRewardPayoutsInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionSetupInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -52444,193 +51830,171 @@ import SoraUI - func didReceive(result: Result) { + func didReceiveCrowdloan(result: Result) { - return cuckoo_manager.call("didReceive(result: Result)", + return cuckoo_manager.call("didReceiveCrowdloan(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(result: result)) + defaultCall: __defaultImplStub!.didReceiveCrowdloan(result: result)) } - func didReceive(priceResult: Result) { + func didReceiveDisplayInfo(result: Result) { - return cuckoo_manager.call("didReceive(priceResult: Result)", - parameters: (priceResult), - escapingParameters: (priceResult), + return cuckoo_manager.call("didReceiveDisplayInfo(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(priceResult: priceResult)) + defaultCall: __defaultImplStub!.didReceiveDisplayInfo(result: result)) } - func didReceive(eraCountdownResult: Result) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("didReceive(eraCountdownResult: Result)", - parameters: (eraCountdownResult), - escapingParameters: (eraCountdownResult), + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceive(eraCountdownResult: eraCountdownResult)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - - struct __StubbingProxy_StakingRewardPayoutsInteractorOutputProtocol: Cuckoo.StubbingProxy { - private let cuckoo_manager: Cuckoo.MockManager - - init(manager: Cuckoo.MockManager) { - self.cuckoo_manager = manager - } - - - func didReceive(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorOutputProtocol.self, method: "didReceive(result: Result)", parameterMatchers: matchers)) - } - - func didReceive(priceResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorOutputProtocol.self, method: "didReceive(priceResult: Result)", parameterMatchers: matchers)) - } - - func didReceive(eraCountdownResult: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: eraCountdownResult) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsInteractorOutputProtocol.self, method: "didReceive(eraCountdownResult: Result)", parameterMatchers: matchers)) - } - - } - - struct __VerificationProxy_StakingRewardPayoutsInteractorOutputProtocol: Cuckoo.VerificationProxy { - private let cuckoo_manager: Cuckoo.MockManager - private let callMatcher: Cuckoo.CallMatcher - private let sourceLocation: Cuckoo.SourceLocation - - init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { - self.cuckoo_manager = manager - self.callMatcher = callMatcher - self.sourceLocation = sourceLocation - } - - - - - @discardableResult - func didReceive(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceive(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(priceResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: priceResult) { $0 }] - return cuckoo_manager.verify("didReceive(priceResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceive(eraCountdownResult: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: eraCountdownResult) { $0 }] - return cuckoo_manager.verify("didReceive(eraCountdownResult: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - } -} - - class StakingRewardPayoutsInteractorOutputProtocolStub: StakingRewardPayoutsInteractorOutputProtocol { - - + func didReceiveBlockNumber(result: Result) { + + return cuckoo_manager.call("didReceiveBlockNumber(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveBlockNumber(result: result)) + + } - func didReceive(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func didReceiveBlockDuration(result: Result) { + + return cuckoo_manager.call("didReceiveBlockDuration(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveBlockDuration(result: result)) + } - func didReceive(priceResult: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func didReceiveLeasingPeriod(result: Result) { + + return cuckoo_manager.call("didReceiveLeasingPeriod(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(result: result)) + } - func didReceive(eraCountdownResult: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func didReceiveLeasingOffset(result: Result) { + + return cuckoo_manager.call("didReceiveLeasingOffset(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveLeasingOffset(result: result)) + } -} - - - - class MockStakingRewardPayoutsWireframeProtocol: StakingRewardPayoutsWireframeProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingRewardPayoutsWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingRewardPayoutsWireframeProtocol - typealias Verification = __VerificationProxy_StakingRewardPayoutsWireframeProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - private var __defaultImplStub: StakingRewardPayoutsWireframeProtocol? - - func enableDefaultImplementation(_ stub: StakingRewardPayoutsWireframeProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() + func didReceiveMinimumBalance(result: Result) { + + return cuckoo_manager.call("didReceiveMinimumBalance(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveMinimumBalance(result: result)) + } - - - + func didReceiveMinimumContribution(result: Result) { + + return cuckoo_manager.call("didReceiveMinimumContribution(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveMinimumContribution(result: result)) + + } - func showRewardDetails(from view: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown) { + func didReceivePriceData(result: Result) { - return cuckoo_manager.call("showRewardDetails(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown)", - parameters: (view, payoutInfo, historyDepth, eraCountdown), - escapingParameters: (view, payoutInfo, historyDepth, eraCountdown), + return cuckoo_manager.call("didReceivePriceData(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showRewardDetails(from: view, payoutInfo: payoutInfo, historyDepth: historyDepth, eraCountdown: eraCountdown)) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - func showPayoutConfirmation(for payouts: [PayoutInfo], from view: ControllerBackedProtocol?) { + func didReceiveFee(result: Result) { - return cuckoo_manager.call("showPayoutConfirmation(for: [PayoutInfo], from: ControllerBackedProtocol?)", - parameters: (payouts, view), - escapingParameters: (payouts, view), + return cuckoo_manager.call("didReceiveFee(result: Result)", + parameters: (result), + escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.showPayoutConfirmation(for: payouts, from: view)) + defaultCall: __defaultImplStub!.didReceiveFee(result: result)) } - struct __StubbingProxy_StakingRewardPayoutsWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -52638,19 +52002,64 @@ import SoraUI } - func showRewardDetails(from view: M1, payoutInfo: M2, historyDepth: M3, eraCountdown: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, PayoutInfo, UInt32, EraCountdown)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == PayoutInfo, M3.MatchedType == UInt32, M4.MatchedType == EraCountdown { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, PayoutInfo, UInt32, EraCountdown)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: payoutInfo) { $0.1 }, wrap(matchable: historyDepth) { $0.2 }, wrap(matchable: eraCountdown) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsWireframeProtocol.self, method: "showRewardDetails(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown)", parameterMatchers: matchers)) + func didReceiveCrowdloan(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveCrowdloan(result: Result)", parameterMatchers: matchers)) } - func showPayoutConfirmation(for payouts: M1, from view: M2) -> Cuckoo.ProtocolStubNoReturnFunction<([PayoutInfo], ControllerBackedProtocol?)> where M1.MatchedType == [PayoutInfo], M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<([PayoutInfo], ControllerBackedProtocol?)>] = [wrap(matchable: payouts) { $0.0 }, wrap(matchable: view) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingRewardPayoutsWireframeProtocol.self, method: "showPayoutConfirmation(for: [PayoutInfo], from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceiveDisplayInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveDisplayInfo(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveBlockNumber(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveBlockNumber(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveBlockDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveBlockDuration(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveLeasingPeriod(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveLeasingOffset(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveMinimumBalance(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveMinimumBalance(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveMinimumContribution(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveMinimumContribution(result: Result)", parameterMatchers: matchers)) + } + + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + } + + func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingRewardPayoutsWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -52665,21 +52074,75 @@ import SoraUI @discardableResult - func showRewardDetails(from view: M1, payoutInfo: M2, historyDepth: M3, eraCountdown: M4) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, PayoutInfo, UInt32, EraCountdown), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == PayoutInfo, M3.MatchedType == UInt32, M4.MatchedType == EraCountdown { - let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, PayoutInfo, UInt32, EraCountdown)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: payoutInfo) { $0.1 }, wrap(matchable: historyDepth) { $0.2 }, wrap(matchable: eraCountdown) { $0.3 }] - return cuckoo_manager.verify("showRewardDetails(from: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveCrowdloan(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveCrowdloan(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func showPayoutConfirmation(for payouts: M1, from view: M2) -> Cuckoo.__DoNotUse<([PayoutInfo], ControllerBackedProtocol?), Void> where M1.MatchedType == [PayoutInfo], M2.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<([PayoutInfo], ControllerBackedProtocol?)>] = [wrap(matchable: payouts) { $0.0 }, wrap(matchable: view) { $0.1 }] - return cuckoo_manager.verify("showPayoutConfirmation(for: [PayoutInfo], from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveDisplayInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveDisplayInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveBlockNumber(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBlockNumber(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveBlockDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBlockDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveLeasingPeriod(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingPeriod(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveLeasingOffset(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingOffset(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveMinimumBalance(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMinimumBalance(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveMinimumContribution(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveMinimumContribution(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingRewardPayoutsWireframeProtocolStub: StakingRewardPayoutsWireframeProtocol { + class CrowdloanContributionSetupInteractorOutputProtocolStub: CrowdloanContributionSetupInteractorOutputProtocol { @@ -52687,13 +52150,67 @@ import SoraUI - func showRewardDetails(from view: ControllerBackedProtocol?, payoutInfo: PayoutInfo, historyDepth: UInt32, eraCountdown: EraCountdown) { + func didReceiveCrowdloan(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func showPayoutConfirmation(for payouts: [PayoutInfo], from view: ControllerBackedProtocol?) { + func didReceiveDisplayInfo(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveAccountInfo(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveBlockNumber(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveBlockDuration(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveLeasingPeriod(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveLeasingOffset(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveMinimumBalance(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveMinimumContribution(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceivePriceData(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveFee(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -52701,19 +52218,19 @@ import SoraUI - class MockStakingPayoutViewModelFactoryProtocol: StakingPayoutViewModelFactoryProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanContributionSetupWireframeProtocol: CrowdloanContributionSetupWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingPayoutViewModelFactoryProtocol + typealias MocksType = CrowdloanContributionSetupWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingPayoutViewModelFactoryProtocol - typealias Verification = __VerificationProxy_StakingPayoutViewModelFactoryProtocol + typealias Stubbing = __StubbingProxy_CrowdloanContributionSetupWireframeProtocol + typealias Verification = __VerificationProxy_CrowdloanContributionSetupWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingPayoutViewModelFactoryProtocol? + private var __defaultImplStub: CrowdloanContributionSetupWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingPayoutViewModelFactoryProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanContributionSetupWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -52726,56 +52243,116 @@ import SoraUI - func createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource { + func showConfirmation(from view: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?) { - return cuckoo_manager.call("createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource", - parameters: (payoutsInfo, priceData, eraCountdown), - escapingParameters: (payoutsInfo, priceData, eraCountdown), + return cuckoo_manager.call("showConfirmation(from: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?)", + parameters: (view, paraId, inputAmount, bonusService), + escapingParameters: (view, paraId, inputAmount, bonusService), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.createPayoutsViewModel(payoutsInfo: payoutsInfo, priceData: priceData, eraCountdown: eraCountdown)) + defaultCall: __defaultImplStub!.showConfirmation(from: view, paraId: paraId, inputAmount: inputAmount, bonusService: bonusService)) } - func timeLeftString(at index: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource { + func showAdditionalBonus(from view: CrowdloanContributionSetupViewProtocol?, for displayInfo: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?) { - return cuckoo_manager.call("timeLeftString(at: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource", - parameters: (index, payoutsInfo, eraCountdown), - escapingParameters: (index, payoutsInfo, eraCountdown), + return cuckoo_manager.call("showAdditionalBonus(from: CrowdloanContributionSetupViewProtocol?, for: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?)", + parameters: (view, displayInfo, inputAmount, delegate, existingService), + escapingParameters: (view, displayInfo, inputAmount, delegate, existingService), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.timeLeftString(at: index, payoutsInfo: payoutsInfo, eraCountdown: eraCountdown)) + defaultCall: __defaultImplStub!.showAdditionalBonus(from: view, for: displayInfo, inputAmount: inputAmount, delegate: delegate, existingService: existingService)) + + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) + + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + + } + + + + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + + return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", + parameters: (url, view, style), + escapingParameters: (url, view, style), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) } - struct __StubbingProxy_StakingPayoutViewModelFactoryProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanContributionSetupWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { self.cuckoo_manager = manager } - - func createPayoutsViewModel(payoutsInfo: M1, priceData: M2, eraCountdown: M3) -> Cuckoo.ProtocolStubFunction<(PayoutsInfo, PriceData?, EraCountdown?), LocalizableResource> where M1.MatchedType == PayoutsInfo, M2.OptionalMatchedType == PriceData, M3.OptionalMatchedType == EraCountdown { - let matchers: [Cuckoo.ParameterMatcher<(PayoutsInfo, PriceData?, EraCountdown?)>] = [wrap(matchable: payoutsInfo) { $0.0 }, wrap(matchable: priceData) { $0.1 }, wrap(matchable: eraCountdown) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutViewModelFactoryProtocol.self, method: "createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource", parameterMatchers: matchers)) + + func showConfirmation(from view: M1, paraId: M2, inputAmount: M3, bonusService: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributionSetupViewProtocol?, ParaId, Decimal, CrowdloanBonusServiceProtocol?)> where M1.OptionalMatchedType == CrowdloanContributionSetupViewProtocol, M2.MatchedType == ParaId, M3.MatchedType == Decimal, M4.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewProtocol?, ParaId, Decimal, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: paraId) { $0.1 }, wrap(matchable: inputAmount) { $0.2 }, wrap(matchable: bonusService) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "showConfirmation(from: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) + } + + func showAdditionalBonus(from view: M1, for displayInfo: M2, inputAmount: M3, delegate: M4, existingService: M5) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanContributionSetupViewProtocol?, CrowdloanDisplayInfo, Decimal, CustomCrowdloanDelegate, CrowdloanBonusServiceProtocol?)> where M1.OptionalMatchedType == CrowdloanContributionSetupViewProtocol, M2.MatchedType == CrowdloanDisplayInfo, M3.MatchedType == Decimal, M4.MatchedType == CustomCrowdloanDelegate, M5.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewProtocol?, CrowdloanDisplayInfo, Decimal, CustomCrowdloanDelegate, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: displayInfo) { $0.1 }, wrap(matchable: inputAmount) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: existingService) { $0.4 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "showAdditionalBonus(from: CrowdloanContributionSetupViewProtocol?, for: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?)", parameterMatchers: matchers)) + } + + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func timeLeftString(at index: M1, payoutsInfo: M2, eraCountdown: M3) -> Cuckoo.ProtocolStubFunction<(Int, PayoutsInfo, EraCountdown?), LocalizableResource> where M1.MatchedType == Int, M2.MatchedType == PayoutsInfo, M3.OptionalMatchedType == EraCountdown { - let matchers: [Cuckoo.ParameterMatcher<(Int, PayoutsInfo, EraCountdown?)>] = [wrap(matchable: index) { $0.0 }, wrap(matchable: payoutsInfo) { $0.1 }, wrap(matchable: eraCountdown) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingPayoutViewModelFactoryProtocol.self, method: "timeLeftString(at: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource", parameterMatchers: matchers)) + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanContributionSetupWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingPayoutViewModelFactoryProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanContributionSetupWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -52790,21 +52367,39 @@ import SoraUI @discardableResult - func createPayoutsViewModel(payoutsInfo: M1, priceData: M2, eraCountdown: M3) -> Cuckoo.__DoNotUse<(PayoutsInfo, PriceData?, EraCountdown?), LocalizableResource> where M1.MatchedType == PayoutsInfo, M2.OptionalMatchedType == PriceData, M3.OptionalMatchedType == EraCountdown { - let matchers: [Cuckoo.ParameterMatcher<(PayoutsInfo, PriceData?, EraCountdown?)>] = [wrap(matchable: payoutsInfo) { $0.0 }, wrap(matchable: priceData) { $0.1 }, wrap(matchable: eraCountdown) { $0.2 }] - return cuckoo_manager.verify("createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showConfirmation(from view: M1, paraId: M2, inputAmount: M3, bonusService: M4) -> Cuckoo.__DoNotUse<(CrowdloanContributionSetupViewProtocol?, ParaId, Decimal, CrowdloanBonusServiceProtocol?), Void> where M1.OptionalMatchedType == CrowdloanContributionSetupViewProtocol, M2.MatchedType == ParaId, M3.MatchedType == Decimal, M4.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewProtocol?, ParaId, Decimal, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: paraId) { $0.1 }, wrap(matchable: inputAmount) { $0.2 }, wrap(matchable: bonusService) { $0.3 }] + return cuckoo_manager.verify("showConfirmation(from: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func timeLeftString(at index: M1, payoutsInfo: M2, eraCountdown: M3) -> Cuckoo.__DoNotUse<(Int, PayoutsInfo, EraCountdown?), LocalizableResource> where M1.MatchedType == Int, M2.MatchedType == PayoutsInfo, M3.OptionalMatchedType == EraCountdown { - let matchers: [Cuckoo.ParameterMatcher<(Int, PayoutsInfo, EraCountdown?)>] = [wrap(matchable: index) { $0.0 }, wrap(matchable: payoutsInfo) { $0.1 }, wrap(matchable: eraCountdown) { $0.2 }] - return cuckoo_manager.verify("timeLeftString(at: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func showAdditionalBonus(from view: M1, for displayInfo: M2, inputAmount: M3, delegate: M4, existingService: M5) -> Cuckoo.__DoNotUse<(CrowdloanContributionSetupViewProtocol?, CrowdloanDisplayInfo, Decimal, CustomCrowdloanDelegate, CrowdloanBonusServiceProtocol?), Void> where M1.OptionalMatchedType == CrowdloanContributionSetupViewProtocol, M2.MatchedType == CrowdloanDisplayInfo, M3.MatchedType == Decimal, M4.MatchedType == CustomCrowdloanDelegate, M5.OptionalMatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanContributionSetupViewProtocol?, CrowdloanDisplayInfo, Decimal, CustomCrowdloanDelegate, CrowdloanBonusServiceProtocol?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: displayInfo) { $0.1 }, wrap(matchable: inputAmount) { $0.2 }, wrap(matchable: delegate) { $0.3 }, wrap(matchable: existingService) { $0.4 }] + return cuckoo_manager.verify("showAdditionalBonus(from: CrowdloanContributionSetupViewProtocol?, for: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingPayoutViewModelFactoryProtocolStub: StakingPayoutViewModelFactoryProtocol { + class CrowdloanContributionSetupWireframeProtocolStub: CrowdloanContributionSetupWireframeProtocol { @@ -52812,14 +52407,32 @@ import SoraUI - func createPayoutsViewModel(payoutsInfo: PayoutsInfo, priceData: PriceData?, eraCountdown: EraCountdown?) -> LocalizableResource { - return DefaultValueRegistry.defaultValue(for: (LocalizableResource).self) + func showConfirmation(from view: CrowdloanContributionSetupViewProtocol?, paraId: ParaId, inputAmount: Decimal, bonusService: CrowdloanBonusServiceProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - func timeLeftString(at index: Int, payoutsInfo: PayoutsInfo, eraCountdown: EraCountdown?) -> LocalizableResource { - return DefaultValueRegistry.defaultValue(for: (LocalizableResource).self) + func showAdditionalBonus(from view: CrowdloanContributionSetupViewProtocol?, for displayInfo: CrowdloanDisplayInfo, inputAmount: Decimal, delegate: CustomCrowdloanDelegate, existingService: CrowdloanBonusServiceProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } } @@ -52828,24 +52441,22 @@ import SoraUI import Cuckoo @testable import novawallet -import BigInt -import Foundation import SoraFoundation - class MockStakingUnbondConfirmViewProtocol: StakingUnbondConfirmViewProtocol, Cuckoo.ProtocolMock { + class MockCrowdloansViewProtocol: CrowdloansViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingUnbondConfirmViewProtocol + typealias MocksType = CrowdloansViewProtocol - typealias Stubbing = __StubbingProxy_StakingUnbondConfirmViewProtocol - typealias Verification = __VerificationProxy_StakingUnbondConfirmViewProtocol + typealias Stubbing = __StubbingProxy_CrowdloansViewProtocol + typealias Verification = __VerificationProxy_CrowdloansViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingUnbondConfirmViewProtocol? + private var __defaultImplStub: CrowdloansViewProtocol? - func enableDefaultImplementation(_ stub: StakingUnbondConfirmViewProtocol) { + func enableDefaultImplementation(_ stub: CrowdloansViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -52854,52 +52465,52 @@ import SoraFoundation - var isSetup: Bool { + var presenter: CrowdloanListPresenterProtocol? { get { - return cuckoo_manager.getter("isSetup", + return cuckoo_manager.getter("presenter", superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.isSetup) + defaultCall: __defaultImplStub!.presenter) } - } - - - - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", + set { + cuckoo_manager.setter("presenter", + value: newValue, superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.controller) + defaultCall: __defaultImplStub!.presenter = newValue) } } - public var localizationManager: LocalizationManagerProtocol? { + var isSetup: Bool { get { - return cuckoo_manager.getter("localizationManager", + return cuckoo_manager.getter("isSetup", superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.localizationManager) + defaultCall: __defaultImplStub!.isSetup) } - set { - cuckoo_manager.setter("localizationManager", - value: newValue, + } + + + + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.localizationManager = newValue) + defaultCall: __defaultImplStub!.controller) } } @@ -52938,91 +52549,61 @@ import SoraFoundation - func didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel) { - - return cuckoo_manager.call("didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveConfirmation(viewModel: viewModel)) - - } - - - - func didReceiveAmount(viewModel: LocalizableResource) { - - return cuckoo_manager.call("didReceiveAmount(viewModel: LocalizableResource)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAmount(viewModel: viewModel)) - - } - - - - func didReceiveFee(viewModel: LocalizableResource?) { + func didReceive(chainInfo: ChainBalanceViewModel) { - return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didReceive(chainInfo: ChainBalanceViewModel)", + parameters: (chainInfo), + escapingParameters: (chainInfo), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didReceive(chainInfo: chainInfo)) } - func didReceiveBonding(duration: LocalizableResource) { + func didReceive(listState: CrowdloanListState) { - return cuckoo_manager.call("didReceiveBonding(duration: LocalizableResource)", - parameters: (duration), - escapingParameters: (duration), + return cuckoo_manager.call("didReceive(listState: CrowdloanListState)", + parameters: (listState), + escapingParameters: (listState), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveBonding(duration: duration)) + defaultCall: __defaultImplStub!.didReceive(listState: listState)) } - func didSetShouldResetRewardsDestination(value: Bool) { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("didSetShouldResetRewardsDestination(value: Bool)", - parameters: (value), - escapingParameters: (value), + return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", + parameters: (message, title, closeAction, view), + escapingParameters: (message, title, closeAction, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didSetShouldResetRewardsDestination(value: value)) + defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) } - public func applyLocalization() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", + parameters: (viewModel, style, view), + escapingParameters: (viewModel, style, view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) } @@ -53057,7 +52638,7 @@ import SoraFoundation } - struct __StubbingProxy_StakingUnbondConfirmViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloansViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -53065,74 +52646,64 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "isSetup") + var presenter: Cuckoo.ProtocolToBeStubbedOptionalProperty { + return .init(manager: cuckoo_manager, name: "presenter") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { - return .init(manager: cuckoo_manager, name: "controller") + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "isSetup") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "controller") } - var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "loadableContentView") } - var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") } - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingUnbondConfirmViewModel)> where M1.MatchedType == StakingUnbondConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel)", parameterMatchers: matchers)) - } - - func didReceiveAmount(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didReceiveAmount(viewModel: LocalizableResource)", parameterMatchers: matchers)) - } - - func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) + func didReceive(chainInfo: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainBalanceViewModel)> where M1.MatchedType == ChainBalanceViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ChainBalanceViewModel)>] = [wrap(matchable: chainInfo) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloansViewProtocol.self, method: "didReceive(chainInfo: ChainBalanceViewModel)", parameterMatchers: matchers)) } - func didReceiveBonding(duration: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: duration) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didReceiveBonding(duration: LocalizableResource)", parameterMatchers: matchers)) + func didReceive(listState: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanListState)> where M1.MatchedType == CrowdloanListState { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanListState)>] = [wrap(matchable: listState) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloansViewProtocol.self, method: "didReceive(listState: CrowdloanListState)", parameterMatchers: matchers)) } - func didSetShouldResetRewardsDestination(value: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: value) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didSetShouldResetRewardsDestination(value: Bool)", parameterMatchers: matchers)) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloansViewProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloansViewProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloansViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) } func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloansViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondConfirmViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloansViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -53145,6 +52716,11 @@ import SoraFoundation + var presenter: Cuckoo.VerifyOptionalProperty { + return .init(manager: cuckoo_manager, name: "presenter", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + var isSetup: Cuckoo.VerifyReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup", callMatcher: callMatcher, sourceLocation: sourceLocation) } @@ -53155,11 +52731,6 @@ import SoraFoundation } - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - - var loadableContentView: Cuckoo.VerifyReadOnlyProperty { return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) } @@ -53172,39 +52743,27 @@ import SoraFoundation @discardableResult - func didReceiveConfirmation(viewModel: M1) -> Cuckoo.__DoNotUse<(StakingUnbondConfirmViewModel), Void> where M1.MatchedType == StakingUnbondConfirmViewModel { - let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondConfirmViewModel)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAmount(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveAmount(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(chainInfo: M1) -> Cuckoo.__DoNotUse<(ChainBalanceViewModel), Void> where M1.MatchedType == ChainBalanceViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ChainBalanceViewModel)>] = [wrap(matchable: chainInfo) { $0 }] + return cuckoo_manager.verify("didReceive(chainInfo: ChainBalanceViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveBonding(duration: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: duration) { $0 }] - return cuckoo_manager.verify("didReceiveBonding(duration: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(listState: M1) -> Cuckoo.__DoNotUse<(CrowdloanListState), Void> where M1.MatchedType == CrowdloanListState { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanListState)>] = [wrap(matchable: listState) { $0 }] + return cuckoo_manager.verify("didReceive(listState: CrowdloanListState)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didSetShouldResetRewardsDestination(value: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: value) { $0 }] - return cuckoo_manager.verify("didSetShouldResetRewardsDestination(value: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] + return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -53222,35 +52781,35 @@ import SoraFoundation } } - class StakingUnbondConfirmViewProtocolStub: StakingUnbondConfirmViewProtocol { + class CrowdloansViewProtocolStub: CrowdloansViewProtocol { - var isSetup: Bool { + var presenter: CrowdloanListPresenterProtocol? { get { - return DefaultValueRegistry.defaultValue(for: (Bool).self) + return DefaultValueRegistry.defaultValue(for: (CrowdloanListPresenterProtocol?).self) } + set { } + } - var controller: UIViewController { + var isSetup: Bool { get { - return DefaultValueRegistry.defaultValue(for: (UIViewController).self) + return DefaultValueRegistry.defaultValue(for: (Bool).self) } } - public var localizationManager: LocalizationManagerProtocol? { + var controller: UIViewController { get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) + return DefaultValueRegistry.defaultValue(for: (UIViewController).self) } - set { } - } @@ -53277,37 +52836,25 @@ import SoraFoundation - func didReceiveConfirmation(viewModel: StakingUnbondConfirmViewModel) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAmount(viewModel: LocalizableResource) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(viewModel: LocalizableResource?) { + func didReceive(chainInfo: ChainBalanceViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveBonding(duration: LocalizableResource) { + func didReceive(listState: CrowdloanListState) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didSetShouldResetRewardsDestination(value: Bool) { + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -53327,19 +52874,19 @@ import SoraFoundation - class MockStakingUnbondConfirmPresenterProtocol: StakingUnbondConfirmPresenterProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanListPresenterProtocol: CrowdloanListPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingUnbondConfirmPresenterProtocol + typealias MocksType = CrowdloanListPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingUnbondConfirmPresenterProtocol - typealias Verification = __VerificationProxy_StakingUnbondConfirmPresenterProtocol + typealias Stubbing = __StubbingProxy_CrowdloanListPresenterProtocol + typealias Verification = __VerificationProxy_CrowdloanListPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingUnbondConfirmPresenterProtocol? + private var __defaultImplStub: CrowdloanListPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingUnbondConfirmPresenterProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanListPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -53352,51 +52899,51 @@ import SoraFoundation - func setup() { + func refresh(shouldReset: Bool) { - return cuckoo_manager.call("setup()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("refresh(shouldReset: Bool)", + parameters: (shouldReset), + escapingParameters: (shouldReset), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setup()) + defaultCall: __defaultImplStub!.refresh(shouldReset: shouldReset)) } - func confirm() { + func selectCrowdloan(_ paraId: ParaId) { - return cuckoo_manager.call("confirm()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("selectCrowdloan(_: ParaId)", + parameters: (paraId), + escapingParameters: (paraId), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.confirm()) + defaultCall: __defaultImplStub!.selectCrowdloan(paraId)) } - func selectAccount() { + func handleYourContributions() { - return cuckoo_manager.call("selectAccount()", + return cuckoo_manager.call("handleYourContributions()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.selectAccount()) + defaultCall: __defaultImplStub!.handleYourContributions()) } - struct __StubbingProxy_StakingUnbondConfirmPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanListPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -53404,24 +52951,24 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + func refresh(shouldReset: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: shouldReset) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "refresh(shouldReset: Bool)", parameterMatchers: matchers)) } - func confirm() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmPresenterProtocol.self, method: "confirm()", parameterMatchers: matchers)) + func selectCrowdloan(_ paraId: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ParaId)> where M1.MatchedType == ParaId { + let matchers: [Cuckoo.ParameterMatcher<(ParaId)>] = [wrap(matchable: paraId) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "selectCrowdloan(_: ParaId)", parameterMatchers: matchers)) } - func selectAccount() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func handleYourContributions() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmPresenterProtocol.self, method: "selectAccount()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListPresenterProtocol.self, method: "handleYourContributions()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondConfirmPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanListPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -53436,27 +52983,27 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func refresh(shouldReset: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: shouldReset) { $0 }] + return cuckoo_manager.verify("refresh(shouldReset: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func confirm() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("confirm()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func selectCrowdloan(_ paraId: M1) -> Cuckoo.__DoNotUse<(ParaId), Void> where M1.MatchedType == ParaId { + let matchers: [Cuckoo.ParameterMatcher<(ParaId)>] = [wrap(matchable: paraId) { $0 }] + return cuckoo_manager.verify("selectCrowdloan(_: ParaId)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func selectAccount() -> Cuckoo.__DoNotUse<(), Void> { + func handleYourContributions() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("selectAccount()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("handleYourContributions()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingUnbondConfirmPresenterProtocolStub: StakingUnbondConfirmPresenterProtocol { + class CrowdloanListPresenterProtocolStub: CrowdloanListPresenterProtocol { @@ -53464,19 +53011,19 @@ import SoraFoundation - func setup() { + func refresh(shouldReset: Bool) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func confirm() { + func selectCrowdloan(_ paraId: ParaId) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func selectAccount() { + func handleYourContributions() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -53484,19 +53031,19 @@ import SoraFoundation - class MockStakingUnbondConfirmInteractorInputProtocol: StakingUnbondConfirmInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanListInteractorInputProtocol: CrowdloanListInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingUnbondConfirmInteractorInputProtocol + typealias MocksType = CrowdloanListInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingUnbondConfirmInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingUnbondConfirmInteractorInputProtocol + typealias Stubbing = __StubbingProxy_CrowdloanListInteractorInputProtocol + typealias Verification = __VerificationProxy_CrowdloanListInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingUnbondConfirmInteractorInputProtocol? + private var __defaultImplStub: CrowdloanListInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingUnbondConfirmInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanListInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -53524,36 +53071,66 @@ import SoraFoundation - func submit(for amount: Decimal, resettingRewardDestination: Bool, chilling: Bool) { + func refresh() { - return cuckoo_manager.call("submit(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", - parameters: (amount, resettingRewardDestination, chilling), - escapingParameters: (amount, resettingRewardDestination, chilling), + return cuckoo_manager.call("refresh()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.submit(for: amount, resettingRewardDestination: resettingRewardDestination, chilling: chilling)) + defaultCall: __defaultImplStub!.refresh()) } - func estimateFee(for amount: Decimal, resettingRewardDestination: Bool, chilling: Bool) { + func saveSelected(chainModel: ChainModel) { - return cuckoo_manager.call("estimateFee(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", - parameters: (amount, resettingRewardDestination, chilling), - escapingParameters: (amount, resettingRewardDestination, chilling), + return cuckoo_manager.call("saveSelected(chainModel: ChainModel)", + parameters: (chainModel), + escapingParameters: (chainModel), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.estimateFee(for: amount, resettingRewardDestination: resettingRewardDestination, chilling: chilling)) + defaultCall: __defaultImplStub!.saveSelected(chainModel: chainModel)) + + } + + + + func becomeOnline() { + + return cuckoo_manager.call("becomeOnline()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.becomeOnline()) + + } + + + + func putOffline() { + + return cuckoo_manager.call("putOffline()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.putOffline()) } - struct __StubbingProxy_StakingUnbondConfirmInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanListInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -53563,22 +53140,32 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func submit(for amount: M1, resettingRewardDestination: M2, chilling: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal, Bool, Bool)> where M1.MatchedType == Decimal, M2.MatchedType == Bool, M3.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Decimal, Bool, Bool)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: resettingRewardDestination) { $0.1 }, wrap(matchable: chilling) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorInputProtocol.self, method: "submit(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", parameterMatchers: matchers)) + func refresh() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "refresh()", parameterMatchers: matchers)) } - func estimateFee(for amount: M1, resettingRewardDestination: M2, chilling: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal, Bool, Bool)> where M1.MatchedType == Decimal, M2.MatchedType == Bool, M3.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Decimal, Bool, Bool)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: resettingRewardDestination) { $0.1 }, wrap(matchable: chilling) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorInputProtocol.self, method: "estimateFee(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", parameterMatchers: matchers)) + func saveSelected(chainModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainModel)> where M1.MatchedType == ChainModel { + let matchers: [Cuckoo.ParameterMatcher<(ChainModel)>] = [wrap(matchable: chainModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "saveSelected(chainModel: ChainModel)", parameterMatchers: matchers)) + } + + func becomeOnline() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "becomeOnline()", parameterMatchers: matchers)) + } + + func putOffline() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorInputProtocol.self, method: "putOffline()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondConfirmInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanListInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -53599,21 +53186,33 @@ import SoraFoundation } @discardableResult - func submit(for amount: M1, resettingRewardDestination: M2, chilling: M3) -> Cuckoo.__DoNotUse<(Decimal, Bool, Bool), Void> where M1.MatchedType == Decimal, M2.MatchedType == Bool, M3.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Decimal, Bool, Bool)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: resettingRewardDestination) { $0.1 }, wrap(matchable: chilling) { $0.2 }] - return cuckoo_manager.verify("submit(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func refresh() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("refresh()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func estimateFee(for amount: M1, resettingRewardDestination: M2, chilling: M3) -> Cuckoo.__DoNotUse<(Decimal, Bool, Bool), Void> where M1.MatchedType == Decimal, M2.MatchedType == Bool, M3.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(Decimal, Bool, Bool)>] = [wrap(matchable: amount) { $0.0 }, wrap(matchable: resettingRewardDestination) { $0.1 }, wrap(matchable: chilling) { $0.2 }] - return cuckoo_manager.verify("estimateFee(for: Decimal, resettingRewardDestination: Bool, chilling: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func saveSelected(chainModel: M1) -> Cuckoo.__DoNotUse<(ChainModel), Void> where M1.MatchedType == ChainModel { + let matchers: [Cuckoo.ParameterMatcher<(ChainModel)>] = [wrap(matchable: chainModel) { $0 }] + return cuckoo_manager.verify("saveSelected(chainModel: ChainModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func becomeOnline() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("becomeOnline()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func putOffline() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("putOffline()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingUnbondConfirmInteractorInputProtocolStub: StakingUnbondConfirmInteractorInputProtocol { + class CrowdloanListInteractorInputProtocolStub: CrowdloanListInteractorInputProtocol { @@ -53627,13 +53226,25 @@ import SoraFoundation - func submit(for amount: Decimal, resettingRewardDestination: Bool, chilling: Bool) { + func refresh() { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func estimateFee(for amount: Decimal, resettingRewardDestination: Bool, chilling: Bool) { + func saveSelected(chainModel: ChainModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func becomeOnline() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func putOffline() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -53641,19 +53252,19 @@ import SoraFoundation - class MockStakingUnbondConfirmInteractorOutputProtocol: StakingUnbondConfirmInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanListInteractorOutputProtocol: CrowdloanListInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingUnbondConfirmInteractorOutputProtocol + typealias MocksType = CrowdloanListInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingUnbondConfirmInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingUnbondConfirmInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_CrowdloanListInteractorOutputProtocol + typealias Verification = __VerificationProxy_CrowdloanListInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingUnbondConfirmInteractorOutputProtocol? + private var __defaultImplStub: CrowdloanListInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingUnbondConfirmInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanListInteractorOutputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -53666,201 +53277,186 @@ import SoraFoundation - func didReceiveStakingLedger(result: Result) { - - return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) - - } - - - - func didReceiveAccountInfo(result: Result) { + func didReceiveCrowdloans(result: Result<[Crowdloan], Error>) { - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", + return cuckoo_manager.call("didReceiveCrowdloans(result: Result<[Crowdloan], Error>)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) + defaultCall: __defaultImplStub!.didReceiveCrowdloans(result: result)) } - func didReceivePriceData(result: Result) { + func didReceiveDisplayInfo(result: Result) { - return cuckoo_manager.call("didReceivePriceData(result: Result)", + return cuckoo_manager.call("didReceiveDisplayInfo(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + defaultCall: __defaultImplStub!.didReceiveDisplayInfo(result: result)) } - func didReceiveExistentialDeposit(result: Result) { + func didReceiveBlockNumber(result: Result) { - return cuckoo_manager.call("didReceiveExistentialDeposit(result: Result)", + return cuckoo_manager.call("didReceiveBlockNumber(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveExistentialDeposit(result: result)) + defaultCall: __defaultImplStub!.didReceiveBlockNumber(result: result)) } - func didReceiveFee(result: Result) { + func didReceiveBlockDuration(result: Result) { - return cuckoo_manager.call("didReceiveFee(result: Result)", + return cuckoo_manager.call("didReceiveBlockDuration(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + defaultCall: __defaultImplStub!.didReceiveBlockDuration(result: result)) } - func didReceiveController(result: Result) { + func didReceiveLeasingPeriod(result: Result) { - return cuckoo_manager.call("didReceiveController(result: Result)", + return cuckoo_manager.call("didReceiveLeasingPeriod(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveController(result: result)) + defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(result: result)) } - func didReceiveStashItem(result: Result) { + func didReceiveLeasingOffset(result: Result) { - return cuckoo_manager.call("didReceiveStashItem(result: Result)", + return cuckoo_manager.call("didReceiveLeasingOffset(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) + defaultCall: __defaultImplStub!.didReceiveLeasingOffset(result: result)) } - func didReceivePayee(result: Result) { + func didReceiveContributions(result: Result) { - return cuckoo_manager.call("didReceivePayee(result: Result)", + return cuckoo_manager.call("didReceiveContributions(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePayee(result: result)) + defaultCall: __defaultImplStub!.didReceiveContributions(result: result)) } - func didReceiveMinBonded(result: Result) { + func didReceiveExternalContributions(result: Result<[ExternalContribution], Error>) { - return cuckoo_manager.call("didReceiveMinBonded(result: Result)", + return cuckoo_manager.call("didReceiveExternalContributions(result: Result<[ExternalContribution], Error>)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveMinBonded(result: result)) + defaultCall: __defaultImplStub!.didReceiveExternalContributions(result: result)) } - func didReceiveNomination(result: Result) { + func didReceiveLeaseInfo(result: Result) { - return cuckoo_manager.call("didReceiveNomination(result: Result)", + return cuckoo_manager.call("didReceiveLeaseInfo(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveNomination(result: result)) + defaultCall: __defaultImplStub!.didReceiveLeaseInfo(result: result)) } - func didReceiveBondingDuration(result: Result) { + func didReceiveSelectedChain(result: Result) { - return cuckoo_manager.call("didReceiveBondingDuration(result: Result)", + return cuckoo_manager.call("didReceiveSelectedChain(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveBondingDuration(result: result)) + defaultCall: __defaultImplStub!.didReceiveSelectedChain(result: result)) } - func didReceiveStakingDuration(result: Result) { + func didReceiveAccountInfo(result: Result) { - return cuckoo_manager.call("didReceiveStakingDuration(result: Result)", + return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStakingDuration(result: result)) + defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) } - func didSubmitUnbonding(result: Result) { + func didReceivePriceData(result: Result?) { - return cuckoo_manager.call("didSubmitUnbonding(result: Result)", + return cuckoo_manager.call("didReceivePriceData(result: Result?)", parameters: (result), escapingParameters: (result), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didSubmitUnbonding(result: result)) + defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) } - struct __StubbingProxy_StakingUnbondConfirmInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanListInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -53868,74 +53464,69 @@ import SoraFoundation } - func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) + func didReceiveCrowdloans(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[Crowdloan], Error>)> where M1.MatchedType == Result<[Crowdloan], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[Crowdloan], Error>)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveCrowdloans(result: Result<[Crowdloan], Error>)", parameterMatchers: matchers)) } - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + func didReceiveDisplayInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveDisplayInfo(result: Result)", parameterMatchers: matchers)) } - func didReceiveExistentialDeposit(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveExistentialDeposit(result: Result)", parameterMatchers: matchers)) + func didReceiveBlockNumber(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveBlockNumber(result: Result)", parameterMatchers: matchers)) } - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + func didReceiveBlockDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveBlockDuration(result: Result)", parameterMatchers: matchers)) } - func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) + func didReceiveLeasingPeriod(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(result: Result)", parameterMatchers: matchers)) } - func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + func didReceiveLeasingOffset(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(result: Result)", parameterMatchers: matchers)) } - func didReceivePayee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceivePayee(result: Result)", parameterMatchers: matchers)) + func didReceiveContributions(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveContributions(result: Result)", parameterMatchers: matchers)) } - func didReceiveMinBonded(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveMinBonded(result: Result)", parameterMatchers: matchers)) + func didReceiveExternalContributions(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result<[ExternalContribution], Error>)> where M1.MatchedType == Result<[ExternalContribution], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[ExternalContribution], Error>)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveExternalContributions(result: Result<[ExternalContribution], Error>)", parameterMatchers: matchers)) } - func didReceiveNomination(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveNomination(result: Result)", parameterMatchers: matchers)) + func didReceiveLeaseInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveLeaseInfo(result: Result)", parameterMatchers: matchers)) } - func didReceiveBondingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveBondingDuration(result: Result)", parameterMatchers: matchers)) + func didReceiveSelectedChain(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveSelectedChain(result: Result)", parameterMatchers: matchers)) } - func didReceiveStakingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didReceiveStakingDuration(result: Result)", parameterMatchers: matchers)) + func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) } - func didSubmitUnbonding(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmInteractorOutputProtocol.self, method: "didSubmitUnbonding(result: Result)", parameterMatchers: matchers)) + func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result?)> where M1.OptionalMatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result?)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondConfirmInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanListInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -53950,87 +53541,81 @@ import SoraFoundation @discardableResult - func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveCrowdloans(result: M1) -> Cuckoo.__DoNotUse<(Result<[Crowdloan], Error>), Void> where M1.MatchedType == Result<[Crowdloan], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[Crowdloan], Error>)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveCrowdloans(result: Result<[Crowdloan], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveDisplayInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveDisplayInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveExistentialDeposit(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveExistentialDeposit(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBlockNumber(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBlockNumber(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBlockDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveBlockDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveLeasingPeriod(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingPeriod(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveLeasingOffset(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingOffset(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceivePayee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePayee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveContributions(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveContributions(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveMinBonded(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveMinBonded(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveExternalContributions(result: M1) -> Cuckoo.__DoNotUse<(Result<[ExternalContribution], Error>), Void> where M1.MatchedType == Result<[ExternalContribution], Error> { + let matchers: [Cuckoo.ParameterMatcher<(Result<[ExternalContribution], Error>)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveExternalContributions(result: Result<[ExternalContribution], Error>)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveNomination(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveNomination(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveLeaseInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveLeaseInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveBondingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBondingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveSelectedChain(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveSelectedChain(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStakingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didSubmitUnbonding(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didSubmitUnbonding(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result?), Void> where M1.OptionalMatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result?)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceivePriceData(result: Result?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingUnbondConfirmInteractorOutputProtocolStub: StakingUnbondConfirmInteractorOutputProtocol { + class CrowdloanListInteractorOutputProtocolStub: CrowdloanListInteractorOutputProtocol { @@ -54038,79 +53623,73 @@ import SoraFoundation - func didReceiveStakingLedger(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAccountInfo(result: Result) { + func didReceiveCrowdloans(result: Result<[Crowdloan], Error>) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceivePriceData(result: Result) { + func didReceiveDisplayInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveExistentialDeposit(result: Result) { + func didReceiveBlockNumber(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveFee(result: Result) { + func didReceiveBlockDuration(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveController(result: Result) { + func didReceiveLeasingPeriod(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStashItem(result: Result) { + func didReceiveLeasingOffset(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceivePayee(result: Result) { + func didReceiveContributions(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveMinBonded(result: Result) { + func didReceiveExternalContributions(result: Result<[ExternalContribution], Error>) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveNomination(result: Result) { + func didReceiveLeaseInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveBondingDuration(result: Result) { + func didReceiveSelectedChain(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStakingDuration(result: Result) { + func didReceiveAccountInfo(result: Result) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didSubmitUnbonding(result: Result) { + func didReceivePriceData(result: Result?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -54118,19 +53697,19 @@ import SoraFoundation - class MockStakingUnbondConfirmWireframeProtocol: StakingUnbondConfirmWireframeProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanListWireframeProtocol: CrowdloanListWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingUnbondConfirmWireframeProtocol + typealias MocksType = CrowdloanListWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingUnbondConfirmWireframeProtocol - typealias Verification = __VerificationProxy_StakingUnbondConfirmWireframeProtocol + typealias Stubbing = __StubbingProxy_CrowdloanListWireframeProtocol + typealias Verification = __VerificationProxy_CrowdloanListWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingUnbondConfirmWireframeProtocol? + private var __defaultImplStub: CrowdloanListWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingUnbondConfirmWireframeProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanListWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -54143,16 +53722,61 @@ import SoraFoundation - func complete(from view: StakingUnbondConfirmViewProtocol?) { + func presentContributionSetup(from view: (ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?) { - return cuckoo_manager.call("complete(from: StakingUnbondConfirmViewProtocol?)", - parameters: (view), - escapingParameters: (view), + return cuckoo_manager.call("presentContributionSetup(from: (ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?)", + parameters: (view, crowdloan, displayInfo), + escapingParameters: (view, crowdloan, displayInfo), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.complete(from: view)) + defaultCall: __defaultImplStub!.presentContributionSetup(from: view, crowdloan: crowdloan, displayInfo: displayInfo)) + + } + + + + func showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from: ControllerBackedProtocol?)", + parameters: (crowdloans, viewInfo, chainAsset, view), + escapingParameters: (crowdloans, viewInfo, chainAsset, view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showYourContributions(crowdloans: crowdloans, viewInfo: viewInfo, chainAsset: chainAsset, from: view)) + + } + + + + func selectChain(from view: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?) { + + return cuckoo_manager.call("selectChain(from: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?)", + parameters: (view, delegate, selectedChainAssetId), + escapingParameters: (view, delegate, selectedChainAssetId), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.selectChain(from: view, delegate: delegate, selectedChainAssetId: selectedChainAssetId)) + + } + + + + func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) { + + return cuckoo_manager.call("showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", + parameters: (view, wallet), + escapingParameters: (view, wallet), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showWalletDetails(from: view, wallet: wallet)) } @@ -54187,7 +53811,7 @@ import SoraFoundation } - struct __StubbingProxy_StakingUnbondConfirmWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanListWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -54195,24 +53819,39 @@ import SoraFoundation } - func complete(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingUnbondConfirmViewProtocol?)> where M1.OptionalMatchedType == StakingUnbondConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmWireframeProtocol.self, method: "complete(from: StakingUnbondConfirmViewProtocol?)", parameterMatchers: matchers)) + func presentContributionSetup(from view: M1, crowdloan: M2, displayInfo: M3) -> Cuckoo.ProtocolStubNoReturnFunction<((ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, Crowdloan, CrowdloanDisplayInfo?)> where M1.OptionalMatchedType == (ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol), M2.MatchedType == Crowdloan, M3.OptionalMatchedType == CrowdloanDisplayInfo { + let matchers: [Cuckoo.ParameterMatcher<((ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, Crowdloan, CrowdloanDisplayInfo?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: crowdloan) { $0.1 }, wrap(matchable: displayInfo) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "presentContributionSetup(from: (ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?)", parameterMatchers: matchers)) + } + + func showYourContributions(crowdloans: M1, viewInfo: M2, chainAsset: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<([Crowdloan], CrowdloansViewInfo, ChainAssetDisplayInfo, ControllerBackedProtocol?)> where M1.MatchedType == [Crowdloan], M2.MatchedType == CrowdloansViewInfo, M3.MatchedType == ChainAssetDisplayInfo, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<([Crowdloan], CrowdloansViewInfo, ChainAssetDisplayInfo, ControllerBackedProtocol?)>] = [wrap(matchable: crowdloans) { $0.0 }, wrap(matchable: viewInfo) { $0.1 }, wrap(matchable: chainAsset) { $0.2 }, wrap(matchable: view) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func selectChain(from view: M1, delegate: M2, selectedChainAssetId: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, AssetSelectionDelegate, ChainAssetId?)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AssetSelectionDelegate, M3.OptionalMatchedType == ChainAssetId { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AssetSelectionDelegate, ChainAssetId?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }, wrap(matchable: selectedChainAssetId) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "selectChain(from: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?)", parameterMatchers: matchers)) + } + + func showWalletDetails(from view: M1, wallet: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?, MetaAccountModel)> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaAccountModel)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: wallet) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondConfirmWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanListWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondConfirmWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanListWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -54227,9 +53866,27 @@ import SoraFoundation @discardableResult - func complete(from view: M1) -> Cuckoo.__DoNotUse<(StakingUnbondConfirmViewProtocol?), Void> where M1.OptionalMatchedType == StakingUnbondConfirmViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondConfirmViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("complete(from: StakingUnbondConfirmViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func presentContributionSetup(from view: M1, crowdloan: M2, displayInfo: M3) -> Cuckoo.__DoNotUse<((ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, Crowdloan, CrowdloanDisplayInfo?), Void> where M1.OptionalMatchedType == (ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol), M2.MatchedType == Crowdloan, M3.OptionalMatchedType == CrowdloanDisplayInfo { + let matchers: [Cuckoo.ParameterMatcher<((ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, Crowdloan, CrowdloanDisplayInfo?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: crowdloan) { $0.1 }, wrap(matchable: displayInfo) { $0.2 }] + return cuckoo_manager.verify("presentContributionSetup(from: (ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showYourContributions(crowdloans: M1, viewInfo: M2, chainAsset: M3, from view: M4) -> Cuckoo.__DoNotUse<([Crowdloan], CrowdloansViewInfo, ChainAssetDisplayInfo, ControllerBackedProtocol?), Void> where M1.MatchedType == [Crowdloan], M2.MatchedType == CrowdloansViewInfo, M3.MatchedType == ChainAssetDisplayInfo, M4.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<([Crowdloan], CrowdloansViewInfo, ChainAssetDisplayInfo, ControllerBackedProtocol?)>] = [wrap(matchable: crowdloans) { $0.0 }, wrap(matchable: viewInfo) { $0.1 }, wrap(matchable: chainAsset) { $0.2 }, wrap(matchable: view) { $0.3 }] + return cuckoo_manager.verify("showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func selectChain(from view: M1, delegate: M2, selectedChainAssetId: M3) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, AssetSelectionDelegate, ChainAssetId?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == AssetSelectionDelegate, M3.OptionalMatchedType == ChainAssetId { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, AssetSelectionDelegate, ChainAssetId?)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: delegate) { $0.1 }, wrap(matchable: selectedChainAssetId) { $0.2 }] + return cuckoo_manager.verify("selectChain(from: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showWalletDetails(from view: M1, wallet: M2) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?, MetaAccountModel), Void> where M1.OptionalMatchedType == ControllerBackedProtocol, M2.MatchedType == MetaAccountModel { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?, MetaAccountModel)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: wallet) { $0.1 }] + return cuckoo_manager.verify("showWalletDetails(from: ControllerBackedProtocol?, wallet: MetaAccountModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -54247,7 +53904,7 @@ import SoraFoundation } } - class StakingUnbondConfirmWireframeProtocolStub: StakingUnbondConfirmWireframeProtocol { + class CrowdloanListWireframeProtocolStub: CrowdloanListWireframeProtocol { @@ -54255,201 +53912,133 @@ import SoraFoundation - func complete(from view: StakingUnbondConfirmViewProtocol?) { + func presentContributionSetup(from view: (ControllerBackedProtocol & AlertPresentable & LoadableViewProtocol)?, crowdloan: Crowdloan, displayInfo: CrowdloanDisplayInfo?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + func showYourContributions(crowdloans: [Crowdloan], viewInfo: CrowdloansViewInfo, chainAsset: ChainAssetDisplayInfo, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func selectChain(from view: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } -} - - -import Cuckoo -@testable import novawallet - -import BigInt -import CommonWallet -import Foundation -import SoraFoundation - - - class MockStakingUnbondSetupViewProtocol: StakingUnbondSetupViewProtocol, Cuckoo.ProtocolMock { - - typealias MocksType = StakingUnbondSetupViewProtocol - - typealias Stubbing = __StubbingProxy_StakingUnbondSetupViewProtocol - typealias Verification = __VerificationProxy_StakingUnbondSetupViewProtocol - - let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - - - private var __defaultImplStub: StakingUnbondSetupViewProtocol? - - func enableDefaultImplementation(_ stub: StakingUnbondSetupViewProtocol) { - __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } - + func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } - + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } - public var localizationManager: LocalizationManagerProtocol? { - get { - return cuckoo_manager.getter("localizationManager", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager) - } - - set { - cuckoo_manager.setter("localizationManager", - value: newValue, - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.localizationManager = newValue) - } - + func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} - +import Cuckoo +@testable import novawallet + +import Foundation +import SoraFoundation + + + class MockCrowdloanYourContributionsViewProtocol: CrowdloanYourContributionsViewProtocol, Cuckoo.ProtocolMock { + typealias MocksType = CrowdloanYourContributionsViewProtocol + typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsViewProtocol + typealias Verification = __VerificationProxy_CrowdloanYourContributionsViewProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func didReceiveAsset(viewModel: LocalizableResource) { - - return cuckoo_manager.call("didReceiveAsset(viewModel: LocalizableResource)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAsset(viewModel: viewModel)) - - } - - - - func didReceiveFee(viewModel: LocalizableResource?) { - - return cuckoo_manager.call("didReceiveFee(viewModel: LocalizableResource?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveFee(viewModel: viewModel)) - + private var __defaultImplStub: CrowdloanYourContributionsViewProtocol? + + func enableDefaultImplementation(_ stub: CrowdloanYourContributionsViewProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + - func didReceiveInput(viewModel: LocalizableResource) { - - return cuckoo_manager.call("didReceiveInput(viewModel: LocalizableResource)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } } - func didReceiveTransferable(viewModel: LocalizableResource?) { - - return cuckoo_manager.call("didReceiveTransferable(viewModel: LocalizableResource?)", - parameters: (viewModel), - escapingParameters: (viewModel), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveTransferable(viewModel: viewModel)) + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } } + + + - func didReceiveBonding(duration: LocalizableResource) { + + func reload(model: CrowdloanYourContributionsViewModel) { - return cuckoo_manager.call("didReceiveBonding(duration: LocalizableResource)", - parameters: (duration), - escapingParameters: (duration), + return cuckoo_manager.call("reload(model: CrowdloanYourContributionsViewModel)", + parameters: (model), + escapingParameters: (model), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveBonding(duration: duration)) + defaultCall: __defaultImplStub!.reload(model: model)) } - public func applyLocalization() { + func reload(returnInIntervals: [FormattedReturnInIntervalsViewModel]) { - return cuckoo_manager.call("applyLocalization()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("reload(returnInIntervals: [FormattedReturnInIntervalsViewModel])", + parameters: (returnInIntervals), + escapingParameters: (returnInIntervals), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.applyLocalization()) + defaultCall: __defaultImplStub!.reload(returnInIntervals: returnInIntervals)) } - struct __StubbingProxy_StakingUnbondSetupViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanYourContributionsViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -54457,54 +54046,29 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - var localizationManager: Cuckoo.ProtocolToBeStubbedOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager") - } - - - func didReceiveAsset(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveAsset(viewModel: LocalizableResource)", parameterMatchers: matchers)) - } - - func didReceiveFee(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveFee(viewModel: LocalizableResource?)", parameterMatchers: matchers)) - } - - func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveInput(viewModel: LocalizableResource)", parameterMatchers: matchers)) - } - - func didReceiveTransferable(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource?)> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveTransferable(viewModel: LocalizableResource?)", parameterMatchers: matchers)) - } - - func didReceiveBonding(duration: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LocalizableResource)> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: duration) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "didReceiveBonding(duration: LocalizableResource)", parameterMatchers: matchers)) + func reload(model: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanYourContributionsViewModel)> where M1.MatchedType == CrowdloanYourContributionsViewModel { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewModel)>] = [wrap(matchable: model) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsViewProtocol.self, method: "reload(model: CrowdloanYourContributionsViewModel)", parameterMatchers: matchers)) } - func applyLocalization() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupViewProtocol.self, method: "applyLocalization()", parameterMatchers: matchers)) + func reload(returnInIntervals: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([FormattedReturnInIntervalsViewModel])> where M1.MatchedType == [FormattedReturnInIntervalsViewModel] { + let matchers: [Cuckoo.ParameterMatcher<([FormattedReturnInIntervalsViewModel])>] = [wrap(matchable: returnInIntervals) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsViewProtocol.self, method: "reload(returnInIntervals: [FormattedReturnInIntervalsViewModel])", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondSetupViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanYourContributionsViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -54526,53 +54090,24 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } - - var localizationManager: Cuckoo.VerifyOptionalProperty { - return .init(manager: cuckoo_manager, name: "localizationManager", callMatcher: callMatcher, sourceLocation: sourceLocation) - } - @discardableResult - func didReceiveAsset(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveAsset(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveFee(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveFee(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveInput(viewModel: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveTransferable(viewModel: M1) -> Cuckoo.__DoNotUse<(LocalizableResource?), Void> where M1.OptionalMatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource?)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("didReceiveTransferable(viewModel: LocalizableResource?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveBonding(duration: M1) -> Cuckoo.__DoNotUse<(LocalizableResource), Void> where M1.MatchedType == LocalizableResource { - let matchers: [Cuckoo.ParameterMatcher<(LocalizableResource)>] = [wrap(matchable: duration) { $0 }] - return cuckoo_manager.verify("didReceiveBonding(duration: LocalizableResource)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload(model: M1) -> Cuckoo.__DoNotUse<(CrowdloanYourContributionsViewModel), Void> where M1.MatchedType == CrowdloanYourContributionsViewModel { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewModel)>] = [wrap(matchable: model) { $0 }] + return cuckoo_manager.verify("reload(model: CrowdloanYourContributionsViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func applyLocalization() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("applyLocalization()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func reload(returnInIntervals: M1) -> Cuckoo.__DoNotUse<([FormattedReturnInIntervalsViewModel]), Void> where M1.MatchedType == [FormattedReturnInIntervalsViewModel] { + let matchers: [Cuckoo.ParameterMatcher<([FormattedReturnInIntervalsViewModel])>] = [wrap(matchable: returnInIntervals) { $0 }] + return cuckoo_manager.verify("reload(returnInIntervals: [FormattedReturnInIntervalsViewModel])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingUnbondSetupViewProtocolStub: StakingUnbondSetupViewProtocol { + class CrowdloanYourContributionsViewProtocolStub: CrowdloanYourContributionsViewProtocol { @@ -54591,17 +54126,6 @@ import SoraFoundation } } - - - - public var localizationManager: LocalizationManagerProtocol? { - get { - return DefaultValueRegistry.defaultValue(for: (LocalizationManagerProtocol?).self) - } - - set { } - - } @@ -54609,37 +54133,13 @@ import SoraFoundation - func didReceiveAsset(viewModel: LocalizableResource) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveFee(viewModel: LocalizableResource?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveInput(viewModel: LocalizableResource) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveTransferable(viewModel: LocalizableResource?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveBonding(duration: LocalizableResource) { + func reload(model: CrowdloanYourContributionsViewModel) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - public func applyLocalization() { + func reload(returnInIntervals: [FormattedReturnInIntervalsViewModel]) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -54647,19 +54147,19 @@ import SoraFoundation - class MockStakingUnbondSetupPresenterProtocol: StakingUnbondSetupPresenterProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanYourContributionsPresenterProtocol: CrowdloanYourContributionsPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingUnbondSetupPresenterProtocol + typealias MocksType = CrowdloanYourContributionsPresenterProtocol - typealias Stubbing = __StubbingProxy_StakingUnbondSetupPresenterProtocol - typealias Verification = __VerificationProxy_StakingUnbondSetupPresenterProtocol + typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsPresenterProtocol + typealias Verification = __VerificationProxy_CrowdloanYourContributionsPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingUnbondSetupPresenterProtocol? + private var __defaultImplStub: CrowdloanYourContributionsPresenterProtocol? - func enableDefaultImplementation(_ stub: StakingUnbondSetupPresenterProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanYourContributionsPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -54685,68 +54185,116 @@ import SoraFoundation } + + struct __StubbingProxy_CrowdloanYourContributionsPresenterProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + } + + } + + struct __VerificationProxy_CrowdloanYourContributionsPresenterProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + @discardableResult + func setup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + } +} + + class CrowdloanYourContributionsPresenterProtocolStub: CrowdloanYourContributionsPresenterProtocol { + + + - func selectAmountPercentage(_ percentage: Float) { - - return cuckoo_manager.call("selectAmountPercentage(_: Float)", - parameters: (percentage), - escapingParameters: (percentage), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.selectAmountPercentage(percentage)) - + + + func setup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) } +} + + + + class MockCrowdloanYourContributionsVMFactoryProtocol: CrowdloanYourContributionsVMFactoryProtocol, Cuckoo.ProtocolMock { + + typealias MocksType = CrowdloanYourContributionsVMFactoryProtocol + typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsVMFactoryProtocol + typealias Verification = __VerificationProxy_CrowdloanYourContributionsVMFactoryProtocol + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func updateAmount(_ newValue: Decimal) { - - return cuckoo_manager.call("updateAmount(_: Decimal)", - parameters: (newValue), - escapingParameters: (newValue), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.updateAmount(newValue)) - + private var __defaultImplStub: CrowdloanYourContributionsVMFactoryProtocol? + + func enableDefaultImplementation(_ stub: CrowdloanYourContributionsVMFactoryProtocol) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + + + - func proceed() { + + + func createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel { - return cuckoo_manager.call("proceed()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel", + parameters: (input, externalContributions, amount, price, locale), + escapingParameters: (input, externalContributions, amount, price, locale), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.createViewModel(input: input, externalContributions: externalContributions, amount: amount, price: price, locale: locale)) } - func close() { + func createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel] { - return cuckoo_manager.call("close()", - parameters: (), - escapingParameters: (), + return cuckoo_manager.call("createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel]", + parameters: (input, externalContributions, metadata), + escapingParameters: (input, externalContributions, metadata), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.close()) + defaultCall: __defaultImplStub!.createReturnInIntervals(input: input, externalContributions: externalContributions, metadata: metadata)) } - struct __StubbingProxy_StakingUnbondSetupPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanYourContributionsVMFactoryProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -54754,34 +54302,19 @@ import SoraFoundation } - func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func selectAmountPercentage(_ percentage: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Float)> where M1.MatchedType == Float { - let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "selectAmountPercentage(_: Float)", parameterMatchers: matchers)) - } - - func updateAmount(_ newValue: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Decimal)> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "updateAmount(_: Decimal)", parameterMatchers: matchers)) - } - - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + func createViewModel(input: M1, externalContributions: M2, amount: M3, price: M4, locale: M5) -> Cuckoo.ProtocolStubFunction<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, Decimal, PriceData?, Locale), CrowdloanYourContributionsViewModel> where M1.MatchedType == CrowdloanYourContributionsViewInput, M2.OptionalMatchedType == [ExternalContribution], M3.MatchedType == Decimal, M4.OptionalMatchedType == PriceData, M5.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, Decimal, PriceData?, Locale)>] = [wrap(matchable: input) { $0.0 }, wrap(matchable: externalContributions) { $0.1 }, wrap(matchable: amount) { $0.2 }, wrap(matchable: price) { $0.3 }, wrap(matchable: locale) { $0.4 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsVMFactoryProtocol.self, method: "createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel", parameterMatchers: matchers)) } - func close() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupPresenterProtocol.self, method: "close()", parameterMatchers: matchers)) + func createReturnInIntervals(input: M1, externalContributions: M2, metadata: M3) -> Cuckoo.ProtocolStubFunction<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, CrowdloanMetadata), [ReturnInIntervalsViewModel]> where M1.MatchedType == CrowdloanYourContributionsViewInput, M2.OptionalMatchedType == [ExternalContribution], M3.MatchedType == CrowdloanMetadata { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, CrowdloanMetadata)>] = [wrap(matchable: input) { $0.0 }, wrap(matchable: externalContributions) { $0.1 }, wrap(matchable: metadata) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsVMFactoryProtocol.self, method: "createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel]", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondSetupPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanYourContributionsVMFactoryProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -54796,39 +54329,21 @@ import SoraFoundation @discardableResult - func setup() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func selectAmountPercentage(_ percentage: M1) -> Cuckoo.__DoNotUse<(Float), Void> where M1.MatchedType == Float { - let matchers: [Cuckoo.ParameterMatcher<(Float)>] = [wrap(matchable: percentage) { $0 }] - return cuckoo_manager.verify("selectAmountPercentage(_: Float)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func updateAmount(_ newValue: M1) -> Cuckoo.__DoNotUse<(Decimal), Void> where M1.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(Decimal)>] = [wrap(matchable: newValue) { $0 }] - return cuckoo_manager.verify("updateAmount(_: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func createViewModel(input: M1, externalContributions: M2, amount: M3, price: M4, locale: M5) -> Cuckoo.__DoNotUse<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, Decimal, PriceData?, Locale), CrowdloanYourContributionsViewModel> where M1.MatchedType == CrowdloanYourContributionsViewInput, M2.OptionalMatchedType == [ExternalContribution], M3.MatchedType == Decimal, M4.OptionalMatchedType == PriceData, M5.MatchedType == Locale { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, Decimal, PriceData?, Locale)>] = [wrap(matchable: input) { $0.0 }, wrap(matchable: externalContributions) { $0.1 }, wrap(matchable: amount) { $0.2 }, wrap(matchable: price) { $0.3 }, wrap(matchable: locale) { $0.4 }] + return cuckoo_manager.verify("createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func close() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("close()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func createReturnInIntervals(input: M1, externalContributions: M2, metadata: M3) -> Cuckoo.__DoNotUse<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, CrowdloanMetadata), [ReturnInIntervalsViewModel]> where M1.MatchedType == CrowdloanYourContributionsViewInput, M2.OptionalMatchedType == [ExternalContribution], M3.MatchedType == CrowdloanMetadata { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanYourContributionsViewInput, [ExternalContribution]?, CrowdloanMetadata)>] = [wrap(matchable: input) { $0.0 }, wrap(matchable: externalContributions) { $0.1 }, wrap(matchable: metadata) { $0.2 }] + return cuckoo_manager.verify("createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel]", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingUnbondSetupPresenterProtocolStub: StakingUnbondSetupPresenterProtocol { + class CrowdloanYourContributionsVMFactoryProtocolStub: CrowdloanYourContributionsVMFactoryProtocol { @@ -54836,51 +54351,33 @@ import SoraFoundation - func setup() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func selectAmountPercentage(_ percentage: Float) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func updateAmount(_ newValue: Decimal) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func proceed() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func createViewModel(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, amount: Decimal, price: PriceData?, locale: Locale) -> CrowdloanYourContributionsViewModel { + return DefaultValueRegistry.defaultValue(for: (CrowdloanYourContributionsViewModel).self) } - func close() { - return DefaultValueRegistry.defaultValue(for: (Void).self) + func createReturnInIntervals(input: CrowdloanYourContributionsViewInput, externalContributions: [ExternalContribution]?, metadata: CrowdloanMetadata) -> [ReturnInIntervalsViewModel] { + return DefaultValueRegistry.defaultValue(for: ([ReturnInIntervalsViewModel]).self) } } - class MockStakingUnbondSetupInteractorInputProtocol: StakingUnbondSetupInteractorInputProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanYourContributionsInteractorInputProtocol: CrowdloanYourContributionsInteractorInputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingUnbondSetupInteractorInputProtocol + typealias MocksType = CrowdloanYourContributionsInteractorInputProtocol - typealias Stubbing = __StubbingProxy_StakingUnbondSetupInteractorInputProtocol - typealias Verification = __VerificationProxy_StakingUnbondSetupInteractorInputProtocol + typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsInteractorInputProtocol + typealias Verification = __VerificationProxy_CrowdloanYourContributionsInteractorInputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingUnbondSetupInteractorInputProtocol? + private var __defaultImplStub: CrowdloanYourContributionsInteractorInputProtocol? - func enableDefaultImplementation(_ stub: StakingUnbondSetupInteractorInputProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanYourContributionsInteractorInputProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -54906,23 +54403,8 @@ import SoraFoundation } - - - func estimateFee() { - - return cuckoo_manager.call("estimateFee()", - parameters: (), - escapingParameters: (), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.estimateFee()) - - } - - struct __StubbingProxy_StakingUnbondSetupInteractorInputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanYourContributionsInteractorInputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -54932,17 +54414,12 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) - } - - func estimateFee() -> Cuckoo.ProtocolStubNoReturnFunction<()> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorInputProtocol.self, method: "estimateFee()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorInputProtocol.self, method: "setup()", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondSetupInteractorInputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanYourContributionsInteractorInputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -54962,16 +54439,10 @@ import SoraFoundation return cuckoo_manager.verify("setup()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - @discardableResult - func estimateFee() -> Cuckoo.__DoNotUse<(), Void> { - let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("estimateFee()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } - class StakingUnbondSetupInteractorInputProtocolStub: StakingUnbondSetupInteractorInputProtocol { + class CrowdloanYourContributionsInteractorInputProtocolStub: CrowdloanYourContributionsInteractorInputProtocol { @@ -54983,176 +54454,140 @@ import SoraFoundation return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - func estimateFee() { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - } - class MockStakingUnbondSetupInteractorOutputProtocol: StakingUnbondSetupInteractorOutputProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanYourContributionsInteractorOutputProtocol: CrowdloanYourContributionsInteractorOutputProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingUnbondSetupInteractorOutputProtocol + typealias MocksType = CrowdloanYourContributionsInteractorOutputProtocol - typealias Stubbing = __StubbingProxy_StakingUnbondSetupInteractorOutputProtocol - typealias Verification = __VerificationProxy_StakingUnbondSetupInteractorOutputProtocol + typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsInteractorOutputProtocol + typealias Verification = __VerificationProxy_CrowdloanYourContributionsInteractorOutputProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingUnbondSetupInteractorOutputProtocol? + private var __defaultImplStub: CrowdloanYourContributionsInteractorOutputProtocol? - func enableDefaultImplementation(_ stub: StakingUnbondSetupInteractorOutputProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanYourContributionsInteractorOutputProtocol) { __defaultImplStub = stub - cuckoo_manager.enableDefaultStubImplementation() - } - - - - - - - - - - func didReceiveStakingLedger(result: Result) { - - return cuckoo_manager.call("didReceiveStakingLedger(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveStakingLedger(result: result)) - + cuckoo_manager.enableDefaultStubImplementation() } + + - func didReceiveAccountInfo(result: Result) { - - return cuckoo_manager.call("didReceiveAccountInfo(result: Result)", - parameters: (result), - escapingParameters: (result), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.didReceiveAccountInfo(result: result)) - - } + - func didReceivePriceData(result: Result) { + func didReceiveExternalContributions(_ externalContributions: [ExternalContribution]) { - return cuckoo_manager.call("didReceivePriceData(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveExternalContributions(_: [ExternalContribution])", + parameters: (externalContributions), + escapingParameters: (externalContributions), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceivePriceData(result: result)) + defaultCall: __defaultImplStub!.didReceiveExternalContributions(externalContributions)) } - func didReceiveBondingDuration(result: Result) { + func didReceiveBlockNumber(_ blockNumber: BlockNumber?) { - return cuckoo_manager.call("didReceiveBondingDuration(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveBlockNumber(_: BlockNumber?)", + parameters: (blockNumber), + escapingParameters: (blockNumber), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveBondingDuration(result: result)) + defaultCall: __defaultImplStub!.didReceiveBlockNumber(blockNumber)) } - func didReceiveExistentialDeposit(result: Result) { + func didReceiveBlockDuration(_ blockDuration: BlockTime) { - return cuckoo_manager.call("didReceiveExistentialDeposit(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveBlockDuration(_: BlockTime)", + parameters: (blockDuration), + escapingParameters: (blockDuration), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveExistentialDeposit(result: result)) + defaultCall: __defaultImplStub!.didReceiveBlockDuration(blockDuration)) } - func didReceiveFee(result: Result) { + func didReceiveLeasingPeriod(_ leasingPeriod: LeasingPeriod) { - return cuckoo_manager.call("didReceiveFee(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveLeasingPeriod(_: LeasingPeriod)", + parameters: (leasingPeriod), + escapingParameters: (leasingPeriod), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveFee(result: result)) + defaultCall: __defaultImplStub!.didReceiveLeasingPeriod(leasingPeriod)) } - func didReceiveController(result: Result) { + func didReceiveLeasingOffset(_ leasingOffset: LeasingOffset) { - return cuckoo_manager.call("didReceiveController(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveLeasingOffset(_: LeasingOffset)", + parameters: (leasingOffset), + escapingParameters: (leasingOffset), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveController(result: result)) + defaultCall: __defaultImplStub!.didReceiveLeasingOffset(leasingOffset)) } - func didReceiveStashItem(result: Result) { + func didReceivePrice(_ priceData: PriceData?) { - return cuckoo_manager.call("didReceiveStashItem(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceivePrice(_: PriceData?)", + parameters: (priceData), + escapingParameters: (priceData), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStashItem(result: result)) + defaultCall: __defaultImplStub!.didReceivePrice(priceData)) } - func didReceiveStakingDuration(result: Result) { + func didReceiveError(_ error: Error) { - return cuckoo_manager.call("didReceiveStakingDuration(result: Result)", - parameters: (result), - escapingParameters: (result), + return cuckoo_manager.call("didReceiveError(_: Error)", + parameters: (error), + escapingParameters: (error), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.didReceiveStakingDuration(result: result)) + defaultCall: __defaultImplStub!.didReceiveError(error)) } - struct __StubbingProxy_StakingUnbondSetupInteractorOutputProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CrowdloanYourContributionsInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -55160,54 +54595,44 @@ import SoraFoundation } - func didReceiveStakingLedger(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveStakingLedger(result: Result)", parameterMatchers: matchers)) - } - - func didReceiveAccountInfo(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveAccountInfo(result: Result)", parameterMatchers: matchers)) - } - - func didReceivePriceData(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceivePriceData(result: Result)", parameterMatchers: matchers)) + func didReceiveExternalContributions(_ externalContributions: M1) -> Cuckoo.ProtocolStubNoReturnFunction<([ExternalContribution])> where M1.MatchedType == [ExternalContribution] { + let matchers: [Cuckoo.ParameterMatcher<([ExternalContribution])>] = [wrap(matchable: externalContributions) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveExternalContributions(_: [ExternalContribution])", parameterMatchers: matchers)) } - func didReceiveBondingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveBondingDuration(result: Result)", parameterMatchers: matchers)) + func didReceiveBlockNumber(_ blockNumber: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BlockNumber?)> where M1.OptionalMatchedType == BlockNumber { + let matchers: [Cuckoo.ParameterMatcher<(BlockNumber?)>] = [wrap(matchable: blockNumber) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveBlockNumber(_: BlockNumber?)", parameterMatchers: matchers)) } - func didReceiveExistentialDeposit(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveExistentialDeposit(result: Result)", parameterMatchers: matchers)) + func didReceiveBlockDuration(_ blockDuration: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(BlockTime)> where M1.MatchedType == BlockTime { + let matchers: [Cuckoo.ParameterMatcher<(BlockTime)>] = [wrap(matchable: blockDuration) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveBlockDuration(_: BlockTime)", parameterMatchers: matchers)) } - func didReceiveFee(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveFee(result: Result)", parameterMatchers: matchers)) + func didReceiveLeasingPeriod(_ leasingPeriod: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LeasingPeriod)> where M1.MatchedType == LeasingPeriod { + let matchers: [Cuckoo.ParameterMatcher<(LeasingPeriod)>] = [wrap(matchable: leasingPeriod) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveLeasingPeriod(_: LeasingPeriod)", parameterMatchers: matchers)) } - func didReceiveController(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveController(result: Result)", parameterMatchers: matchers)) + func didReceiveLeasingOffset(_ leasingOffset: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LeasingOffset)> where M1.MatchedType == LeasingOffset { + let matchers: [Cuckoo.ParameterMatcher<(LeasingOffset)>] = [wrap(matchable: leasingOffset) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveLeasingOffset(_: LeasingOffset)", parameterMatchers: matchers)) } - func didReceiveStashItem(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveStashItem(result: Result)", parameterMatchers: matchers)) + func didReceivePrice(_ priceData: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(PriceData?)> where M1.OptionalMatchedType == PriceData { + let matchers: [Cuckoo.ParameterMatcher<(PriceData?)>] = [wrap(matchable: priceData) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceivePrice(_: PriceData?)", parameterMatchers: matchers)) } - func didReceiveStakingDuration(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupInteractorOutputProtocol.self, method: "didReceiveStakingDuration(result: Result)", parameterMatchers: matchers)) + func didReceiveError(_ error: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Error)> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCrowdloanYourContributionsInteractorOutputProtocol.self, method: "didReceiveError(_: Error)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondSetupInteractorOutputProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CrowdloanYourContributionsInteractorOutputProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -55222,63 +54647,51 @@ import SoraFoundation @discardableResult - func didReceiveStakingLedger(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingLedger(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceiveAccountInfo(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveAccountInfo(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func didReceivePriceData(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceivePriceData(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveExternalContributions(_ externalContributions: M1) -> Cuckoo.__DoNotUse<([ExternalContribution]), Void> where M1.MatchedType == [ExternalContribution] { + let matchers: [Cuckoo.ParameterMatcher<([ExternalContribution])>] = [wrap(matchable: externalContributions) { $0 }] + return cuckoo_manager.verify("didReceiveExternalContributions(_: [ExternalContribution])", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveBondingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveBondingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBlockNumber(_ blockNumber: M1) -> Cuckoo.__DoNotUse<(BlockNumber?), Void> where M1.OptionalMatchedType == BlockNumber { + let matchers: [Cuckoo.ParameterMatcher<(BlockNumber?)>] = [wrap(matchable: blockNumber) { $0 }] + return cuckoo_manager.verify("didReceiveBlockNumber(_: BlockNumber?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveExistentialDeposit(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveExistentialDeposit(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveBlockDuration(_ blockDuration: M1) -> Cuckoo.__DoNotUse<(BlockTime), Void> where M1.MatchedType == BlockTime { + let matchers: [Cuckoo.ParameterMatcher<(BlockTime)>] = [wrap(matchable: blockDuration) { $0 }] + return cuckoo_manager.verify("didReceiveBlockDuration(_: BlockTime)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveFee(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveFee(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveLeasingPeriod(_ leasingPeriod: M1) -> Cuckoo.__DoNotUse<(LeasingPeriod), Void> where M1.MatchedType == LeasingPeriod { + let matchers: [Cuckoo.ParameterMatcher<(LeasingPeriod)>] = [wrap(matchable: leasingPeriod) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingPeriod(_: LeasingPeriod)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveController(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveController(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveLeasingOffset(_ leasingOffset: M1) -> Cuckoo.__DoNotUse<(LeasingOffset), Void> where M1.MatchedType == LeasingOffset { + let matchers: [Cuckoo.ParameterMatcher<(LeasingOffset)>] = [wrap(matchable: leasingOffset) { $0 }] + return cuckoo_manager.verify("didReceiveLeasingOffset(_: LeasingOffset)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStashItem(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStashItem(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceivePrice(_ priceData: M1) -> Cuckoo.__DoNotUse<(PriceData?), Void> where M1.OptionalMatchedType == PriceData { + let matchers: [Cuckoo.ParameterMatcher<(PriceData?)>] = [wrap(matchable: priceData) { $0 }] + return cuckoo_manager.verify("didReceivePrice(_: PriceData?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult - func didReceiveStakingDuration(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { - let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] - return cuckoo_manager.verify("didReceiveStakingDuration(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceiveError(_ error: M1) -> Cuckoo.__DoNotUse<(Error), Void> where M1.MatchedType == Error { + let matchers: [Cuckoo.ParameterMatcher<(Error)>] = [wrap(matchable: error) { $0 }] + return cuckoo_manager.verify("didReceiveError(_: Error)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingUnbondSetupInteractorOutputProtocolStub: StakingUnbondSetupInteractorOutputProtocol { + class CrowdloanYourContributionsInteractorOutputProtocolStub: CrowdloanYourContributionsInteractorOutputProtocol { @@ -55286,55 +54699,43 @@ import SoraFoundation - func didReceiveStakingLedger(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceiveAccountInfo(result: Result) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func didReceivePriceData(result: Result) { + func didReceiveExternalContributions(_ externalContributions: [ExternalContribution]) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveBondingDuration(result: Result) { + func didReceiveBlockNumber(_ blockNumber: BlockNumber?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveExistentialDeposit(result: Result) { + func didReceiveBlockDuration(_ blockDuration: BlockTime) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveFee(result: Result) { + func didReceiveLeasingPeriod(_ leasingPeriod: LeasingPeriod) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveController(result: Result) { + func didReceiveLeasingOffset(_ leasingOffset: LeasingOffset) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStashItem(result: Result) { + func didReceivePrice(_ priceData: PriceData?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } - func didReceiveStakingDuration(result: Result) { + func didReceiveError(_ error: Error) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -55342,19 +54743,19 @@ import SoraFoundation - class MockStakingUnbondSetupWireframeProtocol: StakingUnbondSetupWireframeProtocol, Cuckoo.ProtocolMock { + class MockCrowdloanYourContributionsWireframeProtocol: CrowdloanYourContributionsWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = StakingUnbondSetupWireframeProtocol + typealias MocksType = CrowdloanYourContributionsWireframeProtocol - typealias Stubbing = __StubbingProxy_StakingUnbondSetupWireframeProtocol - typealias Verification = __VerificationProxy_StakingUnbondSetupWireframeProtocol + typealias Stubbing = __StubbingProxy_CrowdloanYourContributionsWireframeProtocol + typealias Verification = __VerificationProxy_CrowdloanYourContributionsWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: StakingUnbondSetupWireframeProtocol? + private var __defaultImplStub: CrowdloanYourContributionsWireframeProtocol? - func enableDefaultImplementation(_ stub: StakingUnbondSetupWireframeProtocol) { + func enableDefaultImplementation(_ stub: CrowdloanYourContributionsWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -55365,68 +54766,89 @@ import SoraFoundation + + struct __StubbingProxy_CrowdloanYourContributionsWireframeProtocol: Cuckoo.StubbingProxy { + private let cuckoo_manager: Cuckoo.MockManager + + init(manager: Cuckoo.MockManager) { + self.cuckoo_manager = manager + } + + + } + + struct __VerificationProxy_CrowdloanYourContributionsWireframeProtocol: Cuckoo.VerificationProxy { + private let cuckoo_manager: Cuckoo.MockManager + private let callMatcher: Cuckoo.CallMatcher + private let sourceLocation: Cuckoo.SourceLocation + + init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) { + self.cuckoo_manager = manager + self.callMatcher = callMatcher + self.sourceLocation = sourceLocation + } + + + + + } +} + + class CrowdloanYourContributionsWireframeProtocolStub: CrowdloanYourContributionsWireframeProtocol { + + + - func close(view: StakingUnbondSetupViewProtocol?) { - - return cuckoo_manager.call("close(view: StakingUnbondSetupViewProtocol?)", - parameters: (view), - escapingParameters: (view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.close(view: view)) - - } +} + + +import Cuckoo +@testable import novawallet + +import Foundation + + + class MockCustomCrowdloanDelegate: CustomCrowdloanDelegate, Cuckoo.ProtocolMock { + typealias MocksType = CustomCrowdloanDelegate + typealias Stubbing = __StubbingProxy_CustomCrowdloanDelegate + typealias Verification = __VerificationProxy_CustomCrowdloanDelegate + + let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) + - func proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal) { - - return cuckoo_manager.call("proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal)", - parameters: (view, amount), - escapingParameters: (view, amount), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.proceed(view: view, amount: amount)) - + private var __defaultImplStub: CustomCrowdloanDelegate? + + func enableDefaultImplementation(_ stub: CustomCrowdloanDelegate) { + __defaultImplStub = stub + cuckoo_manager.enableDefaultStubImplementation() } + + - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) - - } + - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didReceive(bonusService: CrowdloanBonusServiceProtocol) { - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), + return cuckoo_manager.call("didReceive(bonusService: CrowdloanBonusServiceProtocol)", + parameters: (bonusService), + escapingParameters: (bonusService), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) + defaultCall: __defaultImplStub!.didReceive(bonusService: bonusService)) } - struct __StubbingProxy_StakingUnbondSetupWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_CustomCrowdloanDelegate: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -55434,29 +54856,14 @@ import SoraFoundation } - func close(view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingUnbondSetupViewProtocol?)> where M1.OptionalMatchedType == StakingUnbondSetupViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupWireframeProtocol.self, method: "close(view: StakingUnbondSetupViewProtocol?)", parameterMatchers: matchers)) - } - - func proceed(view: M1, amount: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(StakingUnbondSetupViewProtocol?, Decimal)> where M1.OptionalMatchedType == StakingUnbondSetupViewProtocol, M2.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondSetupViewProtocol?, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: amount) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupWireframeProtocol.self, method: "proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal)", parameterMatchers: matchers)) - } - - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingUnbondSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + func didReceive(bonusService: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(CrowdloanBonusServiceProtocol)> where M1.MatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanBonusServiceProtocol)>] = [wrap(matchable: bonusService) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockCustomCrowdloanDelegate.self, method: "didReceive(bonusService: CrowdloanBonusServiceProtocol)", parameterMatchers: matchers)) } } - struct __VerificationProxy_StakingUnbondSetupWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_CustomCrowdloanDelegate: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -55471,33 +54878,15 @@ import SoraFoundation @discardableResult - func close(view: M1) -> Cuckoo.__DoNotUse<(StakingUnbondSetupViewProtocol?), Void> where M1.OptionalMatchedType == StakingUnbondSetupViewProtocol { - let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondSetupViewProtocol?)>] = [wrap(matchable: view) { $0 }] - return cuckoo_manager.verify("close(view: StakingUnbondSetupViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func proceed(view: M1, amount: M2) -> Cuckoo.__DoNotUse<(StakingUnbondSetupViewProtocol?, Decimal), Void> where M1.OptionalMatchedType == StakingUnbondSetupViewProtocol, M2.MatchedType == Decimal { - let matchers: [Cuckoo.ParameterMatcher<(StakingUnbondSetupViewProtocol?, Decimal)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: amount) { $0.1 }] - return cuckoo_manager.verify("proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func didReceive(bonusService: M1) -> Cuckoo.__DoNotUse<(CrowdloanBonusServiceProtocol), Void> where M1.MatchedType == CrowdloanBonusServiceProtocol { + let matchers: [Cuckoo.ParameterMatcher<(CrowdloanBonusServiceProtocol)>] = [wrap(matchable: bonusService) { $0 }] + return cuckoo_manager.verify("didReceive(bonusService: CrowdloanBonusServiceProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class StakingUnbondSetupWireframeProtocolStub: StakingUnbondSetupWireframeProtocol { + class CustomCrowdloanDelegateStub: CustomCrowdloanDelegate { @@ -55505,25 +54894,7 @@ import SoraFoundation - func close(view: StakingUnbondSetupViewProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func proceed(view: StakingUnbondSetupViewProtocol?, amount: Decimal) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { + func didReceive(bonusService: CrowdloanBonusServiceProtocol) { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -55536,74 +54907,192 @@ import Cuckoo import SoraFoundation - class MockUsernameSetupViewProtocol: UsernameSetupViewProtocol, Cuckoo.ProtocolMock { + class MockReferralCrowdloanViewProtocol: ReferralCrowdloanViewProtocol, Cuckoo.ProtocolMock { - typealias MocksType = UsernameSetupViewProtocol + typealias MocksType = ReferralCrowdloanViewProtocol - typealias Stubbing = __StubbingProxy_UsernameSetupViewProtocol - typealias Verification = __VerificationProxy_UsernameSetupViewProtocol + typealias Stubbing = __StubbingProxy_ReferralCrowdloanViewProtocol + typealias Verification = __VerificationProxy_ReferralCrowdloanViewProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: UsernameSetupViewProtocol? + private var __defaultImplStub: ReferralCrowdloanViewProtocol? - func enableDefaultImplementation(_ stub: UsernameSetupViewProtocol) { + func enableDefaultImplementation(_ stub: ReferralCrowdloanViewProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } - + + + + + var isSetup: Bool { + get { + return cuckoo_manager.getter("isSetup", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.isSetup) + } + + } + + + + var controller: UIViewController { + get { + return cuckoo_manager.getter("controller", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.controller) + } + + } + + + + var loadableContentView: UIView! { + get { + return cuckoo_manager.getter("loadableContentView", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.loadableContentView) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return cuckoo_manager.getter("shouldDisableInteractionWhenLoading", + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.shouldDisableInteractionWhenLoading) + } + + } + + + + + + + + func didReceiveLearnMore(viewModel: LearnMoreViewModel) { + + return cuckoo_manager.call("didReceiveLearnMore(viewModel: LearnMoreViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveLearnMore(viewModel: viewModel)) + + } + + + + func didReceiveReferral(viewModel: ReferralCrowdloanViewModel) { + + return cuckoo_manager.call("didReceiveReferral(viewModel: ReferralCrowdloanViewModel)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveReferral(viewModel: viewModel)) + + } + + func didReceiveInput(viewModel: InputViewModelProtocol) { + + return cuckoo_manager.call("didReceiveInput(viewModel: InputViewModelProtocol)", + parameters: (viewModel), + escapingParameters: (viewModel), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveInput(viewModel: viewModel)) + + } - var isSetup: Bool { - get { - return cuckoo_manager.getter("isSetup", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.isSetup) - } + + + func didReceiveShouldInputCode() { + + return cuckoo_manager.call("didReceiveShouldInputCode()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveShouldInputCode()) } - var controller: UIViewController { - get { - return cuckoo_manager.getter("controller", - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.controller) - } + func didReceiveShouldAgreeTerms() { + + return cuckoo_manager.call("didReceiveShouldAgreeTerms()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveShouldAgreeTerms()) } - - + + func didStartLoading() { + + return cuckoo_manager.call("didStartLoading()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didStartLoading()) + + } - func setInput(viewModel: InputViewModelProtocol) { + func didStopLoading() { - return cuckoo_manager.call("setInput(viewModel: InputViewModelProtocol)", - parameters: (viewModel), - escapingParameters: (viewModel), + return cuckoo_manager.call("didStopLoading()", + parameters: (), + escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setInput(viewModel: viewModel)) + defaultCall: __defaultImplStub!.didStopLoading()) } - struct __StubbingProxy_UsernameSetupViewProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ReferralCrowdloanViewProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -55611,24 +55100,64 @@ import SoraFoundation } - var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var isSetup: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "isSetup") } - var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + var controller: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { return .init(manager: cuckoo_manager, name: "controller") } - func setInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(InputViewModelProtocol)> where M1.MatchedType == InputViewModelProtocol { + var loadableContentView: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView") + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.ProtocolToBeStubbedReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading") + } + + + func didReceiveLearnMore(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(LearnMoreViewModel)> where M1.MatchedType == LearnMoreViewModel { + let matchers: [Cuckoo.ParameterMatcher<(LearnMoreViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveLearnMore(viewModel: LearnMoreViewModel)", parameterMatchers: matchers)) + } + + func didReceiveReferral(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ReferralCrowdloanViewModel)> where M1.MatchedType == ReferralCrowdloanViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ReferralCrowdloanViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveReferral(viewModel: ReferralCrowdloanViewModel)", parameterMatchers: matchers)) + } + + func didReceiveInput(viewModel: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(InputViewModelProtocol)> where M1.MatchedType == InputViewModelProtocol { let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupViewProtocol.self, method: "setInput(viewModel: InputViewModelProtocol)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveInput(viewModel: InputViewModelProtocol)", parameterMatchers: matchers)) + } + + func didReceiveShouldInputCode() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveShouldInputCode()", parameterMatchers: matchers)) + } + + func didReceiveShouldAgreeTerms() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didReceiveShouldAgreeTerms()", parameterMatchers: matchers)) + } + + func didStartLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didStartLoading()", parameterMatchers: matchers)) + } + + func didStopLoading() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanViewProtocol.self, method: "didStopLoading()", parameterMatchers: matchers)) } } - struct __VerificationProxy_UsernameSetupViewProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ReferralCrowdloanViewProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -55650,18 +55179,64 @@ import SoraFoundation return .init(manager: cuckoo_manager, name: "controller", callMatcher: callMatcher, sourceLocation: sourceLocation) } + + var loadableContentView: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "loadableContentView", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + + + var shouldDisableInteractionWhenLoading: Cuckoo.VerifyReadOnlyProperty { + return .init(manager: cuckoo_manager, name: "shouldDisableInteractionWhenLoading", callMatcher: callMatcher, sourceLocation: sourceLocation) + } + @discardableResult - func setInput(viewModel: M1) -> Cuckoo.__DoNotUse<(InputViewModelProtocol), Void> where M1.MatchedType == InputViewModelProtocol { + func didReceiveLearnMore(viewModel: M1) -> Cuckoo.__DoNotUse<(LearnMoreViewModel), Void> where M1.MatchedType == LearnMoreViewModel { + let matchers: [Cuckoo.ParameterMatcher<(LearnMoreViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveLearnMore(viewModel: LearnMoreViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveReferral(viewModel: M1) -> Cuckoo.__DoNotUse<(ReferralCrowdloanViewModel), Void> where M1.MatchedType == ReferralCrowdloanViewModel { + let matchers: [Cuckoo.ParameterMatcher<(ReferralCrowdloanViewModel)>] = [wrap(matchable: viewModel) { $0 }] + return cuckoo_manager.verify("didReceiveReferral(viewModel: ReferralCrowdloanViewModel)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveInput(viewModel: M1) -> Cuckoo.__DoNotUse<(InputViewModelProtocol), Void> where M1.MatchedType == InputViewModelProtocol { let matchers: [Cuckoo.ParameterMatcher<(InputViewModelProtocol)>] = [wrap(matchable: viewModel) { $0 }] - return cuckoo_manager.verify("setInput(viewModel: InputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("didReceiveInput(viewModel: InputViewModelProtocol)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveShouldInputCode() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didReceiveShouldInputCode()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didReceiveShouldAgreeTerms() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didReceiveShouldAgreeTerms()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didStartLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStartLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func didStopLoading() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("didStopLoading()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class UsernameSetupViewProtocolStub: UsernameSetupViewProtocol { + class ReferralCrowdloanViewProtocolStub: ReferralCrowdloanViewProtocol { @@ -55680,6 +55255,24 @@ import SoraFoundation } } + + + + var loadableContentView: UIView! { + get { + return DefaultValueRegistry.defaultValue(for: (UIView?).self) + } + + } + + + + var shouldDisableInteractionWhenLoading: Bool { + get { + return DefaultValueRegistry.defaultValue(for: (Bool).self) + } + + } @@ -55687,7 +55280,43 @@ import SoraFoundation - func setInput(viewModel: InputViewModelProtocol) { + func didReceiveLearnMore(viewModel: LearnMoreViewModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveReferral(viewModel: ReferralCrowdloanViewModel) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveInput(viewModel: InputViewModelProtocol) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveShouldInputCode() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didReceiveShouldAgreeTerms() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStartLoading() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func didStopLoading() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -55695,19 +55324,19 @@ import SoraFoundation - class MockUsernameSetupPresenterProtocol: UsernameSetupPresenterProtocol, Cuckoo.ProtocolMock { + class MockReferralCrowdloanPresenterProtocol: ReferralCrowdloanPresenterProtocol, Cuckoo.ProtocolMock { - typealias MocksType = UsernameSetupPresenterProtocol + typealias MocksType = ReferralCrowdloanPresenterProtocol - typealias Stubbing = __StubbingProxy_UsernameSetupPresenterProtocol - typealias Verification = __VerificationProxy_UsernameSetupPresenterProtocol + typealias Stubbing = __StubbingProxy_ReferralCrowdloanPresenterProtocol + typealias Verification = __VerificationProxy_ReferralCrowdloanPresenterProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: UsernameSetupPresenterProtocol? + private var __defaultImplStub: ReferralCrowdloanPresenterProtocol? - func enableDefaultImplementation(_ stub: UsernameSetupPresenterProtocol) { + func enableDefaultImplementation(_ stub: ReferralCrowdloanPresenterProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -55735,21 +55364,96 @@ import SoraFoundation - func proceed() { + func update(referralCode: String) { - return cuckoo_manager.call("proceed()", + return cuckoo_manager.call("update(referralCode: String)", + parameters: (referralCode), + escapingParameters: (referralCode), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.update(referralCode: referralCode)) + + } + + + + func applyDefaultCode() { + + return cuckoo_manager.call("applyDefaultCode()", parameters: (), escapingParameters: (), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed()) + defaultCall: __defaultImplStub!.applyDefaultCode()) + + } + + + + func applyInputCode() { + + return cuckoo_manager.call("applyInputCode()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.applyInputCode()) + + } + + + + func setTermsAgreed(value: Bool) { + + return cuckoo_manager.call("setTermsAgreed(value: Bool)", + parameters: (value), + escapingParameters: (value), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.setTermsAgreed(value: value)) + + } + + + + func presentTerms() { + + return cuckoo_manager.call("presentTerms()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentTerms()) + + } + + + + func presentLearnMore() { + + return cuckoo_manager.call("presentLearnMore()", + parameters: (), + escapingParameters: (), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.presentLearnMore()) } - struct __StubbingProxy_UsernameSetupPresenterProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ReferralCrowdloanPresenterProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -55759,17 +55463,42 @@ import SoraFoundation func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "setup()", parameterMatchers: matchers)) } - func proceed() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + func update(referralCode: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(String)> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: referralCode) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "update(referralCode: String)", parameterMatchers: matchers)) + } + + func applyDefaultCode() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] - return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupPresenterProtocol.self, method: "proceed()", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "applyDefaultCode()", parameterMatchers: matchers)) + } + + func applyInputCode() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "applyInputCode()", parameterMatchers: matchers)) + } + + func setTermsAgreed(value: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Bool)> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: value) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "setTermsAgreed(value: Bool)", parameterMatchers: matchers)) + } + + func presentTerms() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "presentTerms()", parameterMatchers: matchers)) + } + + func presentLearnMore() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanPresenterProtocol.self, method: "presentLearnMore()", parameterMatchers: matchers)) } } - struct __VerificationProxy_UsernameSetupPresenterProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ReferralCrowdloanPresenterProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -55790,15 +55519,45 @@ import SoraFoundation } @discardableResult - func proceed() -> Cuckoo.__DoNotUse<(), Void> { + func update(referralCode: M1) -> Cuckoo.__DoNotUse<(String), Void> where M1.MatchedType == String { + let matchers: [Cuckoo.ParameterMatcher<(String)>] = [wrap(matchable: referralCode) { $0 }] + return cuckoo_manager.verify("update(referralCode: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func applyDefaultCode() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] - return cuckoo_manager.verify("proceed()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + return cuckoo_manager.verify("applyDefaultCode()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func applyInputCode() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("applyInputCode()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func setTermsAgreed(value: M1) -> Cuckoo.__DoNotUse<(Bool), Void> where M1.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(Bool)>] = [wrap(matchable: value) { $0 }] + return cuckoo_manager.verify("setTermsAgreed(value: Bool)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentTerms() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentTerms()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func presentLearnMore() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify("presentLearnMore()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } } } - class UsernameSetupPresenterProtocolStub: UsernameSetupPresenterProtocol { + class ReferralCrowdloanPresenterProtocolStub: ReferralCrowdloanPresenterProtocol { @@ -55812,7 +55571,37 @@ import SoraFoundation - func proceed() { + func update(referralCode: String) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func applyDefaultCode() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func applyInputCode() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func setTermsAgreed(value: Bool) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentTerms() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func presentLearnMore() { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -55820,19 +55609,19 @@ import SoraFoundation - class MockUsernameSetupWireframeProtocol: UsernameSetupWireframeProtocol, Cuckoo.ProtocolMock { + class MockReferralCrowdloanWireframeProtocol: ReferralCrowdloanWireframeProtocol, Cuckoo.ProtocolMock { - typealias MocksType = UsernameSetupWireframeProtocol + typealias MocksType = ReferralCrowdloanWireframeProtocol - typealias Stubbing = __StubbingProxy_UsernameSetupWireframeProtocol - typealias Verification = __VerificationProxy_UsernameSetupWireframeProtocol + typealias Stubbing = __StubbingProxy_ReferralCrowdloanWireframeProtocol + typealias Verification = __VerificationProxy_ReferralCrowdloanWireframeProtocol let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: false) - private var __defaultImplStub: UsernameSetupWireframeProtocol? + private var __defaultImplStub: ReferralCrowdloanWireframeProtocol? - func enableDefaultImplementation(_ stub: UsernameSetupWireframeProtocol) { + func enableDefaultImplementation(_ stub: ReferralCrowdloanWireframeProtocol) { __defaultImplStub = stub cuckoo_manager.enableDefaultStubImplementation() } @@ -55845,16 +55634,31 @@ import SoraFoundation - func proceed(from view: UsernameSetupViewProtocol?, walletName: String) { + func complete(on view: ReferralCrowdloanViewProtocol?) { - return cuckoo_manager.call("proceed(from: UsernameSetupViewProtocol?, walletName: String)", - parameters: (view, walletName), - escapingParameters: (view, walletName), + return cuckoo_manager.call("complete(on: ReferralCrowdloanViewProtocol?)", + parameters: (view), + escapingParameters: (view), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.proceed(from: view, walletName: walletName)) + defaultCall: __defaultImplStub!.complete(on: view)) + + } + + + + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + + return cuckoo_manager.call("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", + parameters: (url, view, style), + escapingParameters: (url, view, style), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showWeb(url: url, from: view, style: style)) } @@ -55889,7 +55693,7 @@ import SoraFoundation } - struct __StubbingProxy_UsernameSetupWireframeProtocol: Cuckoo.StubbingProxy { + struct __StubbingProxy_ReferralCrowdloanWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager init(manager: Cuckoo.MockManager) { @@ -55897,24 +55701,29 @@ import SoraFoundation } - func proceed(from view: M1, walletName: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(UsernameSetupViewProtocol?, String)> where M1.OptionalMatchedType == UsernameSetupViewProtocol, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(UsernameSetupViewProtocol?, String)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: walletName) { $0.1 }] - return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupWireframeProtocol.self, method: "proceed(from: UsernameSetupViewProtocol?, walletName: String)", parameterMatchers: matchers)) + func complete(on view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ReferralCrowdloanViewProtocol?)> where M1.OptionalMatchedType == ReferralCrowdloanViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ReferralCrowdloanViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanWireframeProtocol.self, method: "complete(on: ReferralCrowdloanViewProtocol?)", parameterMatchers: matchers)) + } + + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(URL, ControllerBackedProtocol, WebPresentableStyle)> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanWireframeProtocol.self, method: "showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", parameterMatchers: matchers)) } func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockUsernameSetupWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + return .init(stub: cuckoo_manager.createStub(for: MockReferralCrowdloanWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } } - struct __VerificationProxy_UsernameSetupWireframeProtocol: Cuckoo.VerificationProxy { + struct __VerificationProxy_ReferralCrowdloanWireframeProtocol: Cuckoo.VerificationProxy { private let cuckoo_manager: Cuckoo.MockManager private let callMatcher: Cuckoo.CallMatcher private let sourceLocation: Cuckoo.SourceLocation @@ -55929,9 +55738,15 @@ import SoraFoundation @discardableResult - func proceed(from view: M1, walletName: M2) -> Cuckoo.__DoNotUse<(UsernameSetupViewProtocol?, String), Void> where M1.OptionalMatchedType == UsernameSetupViewProtocol, M2.MatchedType == String { - let matchers: [Cuckoo.ParameterMatcher<(UsernameSetupViewProtocol?, String)>] = [wrap(matchable: view) { $0.0 }, wrap(matchable: walletName) { $0.1 }] - return cuckoo_manager.verify("proceed(from: UsernameSetupViewProtocol?, walletName: String)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func complete(on view: M1) -> Cuckoo.__DoNotUse<(ReferralCrowdloanViewProtocol?), Void> where M1.OptionalMatchedType == ReferralCrowdloanViewProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ReferralCrowdloanViewProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("complete(on: ReferralCrowdloanViewProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showWeb(url: M1, from view: M2, style: M3) -> Cuckoo.__DoNotUse<(URL, ControllerBackedProtocol, WebPresentableStyle), Void> where M1.MatchedType == URL, M2.MatchedType == ControllerBackedProtocol, M3.MatchedType == WebPresentableStyle { + let matchers: [Cuckoo.ParameterMatcher<(URL, ControllerBackedProtocol, WebPresentableStyle)>] = [wrap(matchable: url) { $0.0 }, wrap(matchable: view) { $0.1 }, wrap(matchable: style) { $0.2 }] + return cuckoo_manager.verify("showWeb(url: URL, from: ControllerBackedProtocol, style: WebPresentableStyle)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -55949,7 +55764,7 @@ import SoraFoundation } } - class UsernameSetupWireframeProtocolStub: UsernameSetupWireframeProtocol { + class ReferralCrowdloanWireframeProtocolStub: ReferralCrowdloanWireframeProtocol { @@ -55957,7 +55772,13 @@ import SoraFoundation - func proceed(from view: UsernameSetupViewProtocol?, walletName: String) { + func complete(on view: ReferralCrowdloanViewProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { return DefaultValueRegistry.defaultValue(for: (Void).self) } diff --git a/novawalletTests/Modules/Crowdloan/CrowdloanList/CrowdloanListTests.swift b/novawalletTests/Modules/Crowdloan/CrowdloanList/CrowdloanListTests.swift index 3874edb91a..e71d1d1c99 100644 --- a/novawalletTests/Modules/Crowdloan/CrowdloanList/CrowdloanListTests.swift +++ b/novawalletTests/Modules/Crowdloan/CrowdloanList/CrowdloanListTests.swift @@ -89,7 +89,7 @@ class CrowdloanListTests: XCTestCase { func testCrowdloansSuccessRetrieving() throws { // given - let view = MockCrowdloanListViewProtocol() + let view = MockCrowdloansViewProtocol() let wireframe = MockCrowdloanListWireframeProtocol() let expectedActiveParaIds: Set = activeCrowdloans @@ -106,15 +106,10 @@ class CrowdloanListTests: XCTestCase { let chainCompletionExpectation = XCTestExpectation() let listCompletionExpectation = XCTestExpectation() - let walletSwitchReceiveExpectation = XCTestExpectation() stub(view) { stub in stub.isSetup.get.thenReturn(false, true) - stub.didReceive(walletSwitchViewModel: any()).then { state in - walletSwitchReceiveExpectation.fulfill() - } - stub.didReceive(listState: any()).then { state in if case let .loaded(viewModel) = state { actualViewModel = viewModel @@ -140,7 +135,7 @@ class CrowdloanListTests: XCTestCase { // then - wait(for: [listCompletionExpectation, chainCompletionExpectation, walletSwitchReceiveExpectation], timeout: 10) + wait(for: [listCompletionExpectation, chainCompletionExpectation], timeout: 10) let yourContributionsCount: Int = { let yourContribution = actualViewModel!.sections[0] @@ -179,7 +174,7 @@ class CrowdloanListTests: XCTestCase { } private func createPresenter( - for view: MockCrowdloanListViewProtocol, + for view: MockCrowdloansViewProtocol, wireframe: MockCrowdloanListWireframeProtocol ) throws -> CrowdloanListPresenter? { let localizationManager = LocalizationManager.shared @@ -213,6 +208,7 @@ class CrowdloanListTests: XCTestCase { let presenter = CrowdloanListPresenter( interactor: interactor, wireframe: wireframe, + wallet: selectedAccount, viewModelFactory: viewModelFactory, localizationManager: localizationManager, crowdloansCalculator: CrowdloansCalculator(), From 8fd31dd9fb859319d6cc2ced7190042e7031bbad Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 6 Oct 2022 09:29:15 +0500 Subject: [PATCH 013/229] fetch tracks --- Podfile | 4 +- Podfile.lock | 27 ++-- novawallet.xcodeproj/project.pbxproj | 36 +++++- ...gPath.swift => Referenda+CodingPath.swift} | 4 + .../Types/Referenda/ReferendaCurve.swift | 50 ++++++++ .../Types/Referenda/ReferendaTrackInfo.swift | 29 +++++ .../Types/Referenda/ReferendumInfo.swift | 38 ++++-- .../Governance/Model/ReferendumLocal.swift | 54 ++++++++ .../Operation/Gov2OperationFactory.swift | 121 ++++++++++++++++++ .../GovernanceOperationProtocols.swift | 10 ++ .../ReferendumFetchTests.swift | 41 ++++++ 11 files changed, 384 insertions(+), 30 deletions(-) rename novawallet/Common/Substrate/Types/Referenda/{Referenda+StorageCodingPath.swift => Referenda+CodingPath.swift} (58%) create mode 100644 novawallet/Common/Substrate/Types/Referenda/ReferendaCurve.swift create mode 100644 novawallet/Common/Substrate/Types/Referenda/ReferendaTrackInfo.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift diff --git a/Podfile b/Podfile index dfdb533b42..3e3f144e3f 100644 --- a/Podfile +++ b/Podfile @@ -4,7 +4,7 @@ platform :ios, '13.0' abstract_target 'novawalletAll' do use_frameworks! - pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '1.4.0' + pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :commit => '9063bd531492726097597e442db0f04cd2d8210d' pod 'SwiftLint' pod 'R.swift', :inhibit_warnings => true pod 'SoraKeystore', '~> 1.0.0' @@ -27,7 +27,7 @@ abstract_target 'novawalletAll' do inherit! :search_paths pod 'Cuckoo' - pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '1.4.0' + pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :commit => '9063bd531492726097597e442db0f04cd2d8210d' pod 'SoraFoundation', '~> 1.0.0' pod 'R.swift', :inhibit_warnings => true pod 'FireMock', :inhibit_warnings => true diff --git a/Podfile.lock b/Podfile.lock index f2d7c52279..f8a944997a 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -99,7 +99,7 @@ PODS: - SoraUI/Skrull (1.11.1) - Sourcery (1.4.1) - Starscream (4.0.5) - - SubstrateSdk (1.4.0): + - SubstrateSdk (1.4.1): - BigInt (~> 5.0) - IrohaCrypto/ed25519 (~> 0.9.0) - IrohaCrypto/Scrypt (~> 0.9.0) @@ -137,7 +137,7 @@ DEPENDENCIES: - SoraUI (from `https://github.com/ERussel/UIkit-iOS.git`, tag `1.11.1`) - Sourcery (~> 1.4) - Starscream (from `https://github.com/ERussel/Starscream.git`, tag `4.0.5`) - - SubstrateSdk (from `https://github.com/nova-wallet/substrate-sdk-ios.git`, tag `1.4.0`) + - SubstrateSdk (from `https://github.com/nova-wallet/substrate-sdk-ios.git`, commit `9063bd531492726097597e442db0f04cd2d8210d`) - SVGKit (from `https://github.com/SVGKit/SVGKit.git`, tag `3.0.0`) - SwiftFormat/CLI (~> 0.47.13) - SwiftLint @@ -145,24 +145,21 @@ DEPENDENCIES: - SwiftyBeaver SPEC REPOS: - https://github.com/CocoaPods/Specs.git: - - BigInt - - IrohaCrypto - - keccak.c - - scrypt.c - - secp256k1.c - - TweetNacl - - xxHash-Swift trunk: + - BigInt - Charts - CocoaLumberjack - Cuckoo - FireMock + - IrohaCrypto + - keccak.c - Kingfisher - R.swift - R.swift.Library - ReachabilitySwift - RobinHood + - scrypt.c + - secp256k1.c - SnapKit - SoraFoundation - SoraKeystore @@ -170,6 +167,8 @@ SPEC REPOS: - SwiftFormat - SwiftLint - SwiftyBeaver + - TweetNacl + - xxHash-Swift EXTERNAL SOURCES: CommonWallet: @@ -182,8 +181,8 @@ EXTERNAL SOURCES: :git: https://github.com/ERussel/Starscream.git :tag: 4.0.5 SubstrateSdk: + :commit: 9063bd531492726097597e442db0f04cd2d8210d :git: https://github.com/nova-wallet/substrate-sdk-ios.git - :tag: 1.4.0 SVGKit: :git: https://github.com/SVGKit/SVGKit.git :tag: 3.0.0 @@ -201,8 +200,8 @@ CHECKOUT OPTIONS: :git: https://github.com/ERussel/Starscream.git :tag: 4.0.5 SubstrateSdk: + :commit: 9063bd531492726097597e442db0f04cd2d8210d :git: https://github.com/nova-wallet/substrate-sdk-ios.git - :tag: 1.4.0 SVGKit: :git: https://github.com/SVGKit/SVGKit.git :tag: 3.0.0 @@ -232,7 +231,7 @@ SPEC CHECKSUMS: SoraUI: e5ceb2cffe40145e589aa464e2e0a8d054011e0b Sourcery: db66600e8b285c427701821598d07cf3c7e6c476 Starscream: 8cc648110705c09a15f0de84352c7f9595b7cb05 - SubstrateSdk: 2335047caaddbd33b4cb38e0604d325989d1023c + SubstrateSdk: 8a3e490b078413fc444706899c751766a22c7821 SVGKit: 132b010efbf57ec345309fe4a7f627c0a40c5d63 SwiftFormat: 73573b89257437c550b03d934889725fbf8f75e5 SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 @@ -241,6 +240,6 @@ SPEC CHECKSUMS: TweetNacl: 3abf4d1d2082b0114e7a67410e300892448951e6 xxHash-Swift: 30bd6a7507b3b7348a277c49b1cb6346c2905ec7 -PODFILE CHECKSUM: 7f7a144b623e89cffdcf1bdc1bdbc2d88d2493df +PODFILE CHECKSUM: 4e7796fb71944def78c45a246b810d31342cd2fa COCOAPODS: 1.11.3 diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index dc0af10ee7..cf46d0179d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1145,7 +1145,7 @@ 847A25BF28D7C2A2006AC9F5 /* AccountIdCodingWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25BE28D7C2A2006AC9F5 /* AccountIdCodingWrapper.swift */; }; 847A25C328D84A9C006AC9F5 /* ReferendumFetchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */; }; 847A25C628D84BE2006AC9F5 /* Referenda.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C528D84BE2006AC9F5 /* Referenda.swift */; }; - 847A25C828D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */; }; + 847A25C828D84C0A006AC9F5 /* Referenda+CodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C728D84C0A006AC9F5 /* Referenda+CodingPath.swift */; }; 847A25CA28D85204006AC9F5 /* ReferendumInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */; }; 847A6C0928817DC700477F77 /* AssetListBaseInteractorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A6C0828817DC700477F77 /* AssetListBaseInteractorProtocol.swift */; }; 847A6C0B28817E4000477F77 /* AssetListBaseInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A6C0A28817E4000477F77 /* AssetListBaseInteractor.swift */; }; @@ -1507,6 +1507,9 @@ 849FA21628A26CB500F83EAA /* CountdownTimerMediator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849FA21528A26CB500F83EAA /* CountdownTimerMediator.swift */; }; 84A04622277DE83E000B24DA /* DAppListErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A04621277DE83E000B24DA /* DAppListErrorView.swift */; }; 84A15489262888CA0050D557 /* IdentityOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A15488262888CA0050D557 /* IdentityOperationFactory.swift */; }; + 84A1742428ED3CF70096F943 /* ReferendumLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A1742328ED3CF70096F943 /* ReferendumLocal.swift */; }; + 84A1742728ED607B0096F943 /* GovernanceOperationProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */; }; + 84A1742928ED625D0096F943 /* Gov2OperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */; }; 84A2A60A26B82B35000C6C6C /* ValidatorOperationFactory+Protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A2A60926B82B35000C6C6C /* ValidatorOperationFactory+Protocol.swift */; }; 84A2C90224E07E440020D3B7 /* CryptoType+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A2C90124E07E440020D3B7 /* CryptoType+Utils.swift */; }; 84A2C90424E07F400020D3B7 /* AccountOperationFactoryError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A2C90324E07F400020D3B7 /* AccountOperationFactoryError.swift */; }; @@ -1705,6 +1708,8 @@ 84C3F77B2601F08B00D47501 /* NominationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C3F77A2601F08B00D47501 /* NominationViewModel.swift */; }; 84C3F7832602086100D47501 /* StakingViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C3F7822602086100D47501 /* StakingViewState.swift */; }; 84C3F78C26020DE800D47501 /* StakingStateMachineProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C3F78B26020DE800D47501 /* StakingStateMachineProtocols.swift */; }; + 84C41F3628EDADE000DB1CD3 /* ReferendaTrackInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C41F3528EDADE000DB1CD3 /* ReferendaTrackInfo.swift */; }; + 84C41F3828EDB80700DB1CD3 /* ReferendaCurve.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C41F3728EDB80700DB1CD3 /* ReferendaCurve.swift */; }; 84C4C2D7255D2B780045B582 /* PinChangeWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C4C2D6255D2B780045B582 /* PinChangeWireframe.swift */; }; 84C4C2F9255DB9510045B582 /* PinChangeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C4C2F8255DB9510045B582 /* PinChangeInteractor.swift */; }; 84C515FB26D84F8C000DBA45 /* AccountImportWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C515FA26D84F8C000DBA45 /* AccountImportWrapper.swift */; }; @@ -3927,7 +3932,7 @@ 847A25BE28D7C2A2006AC9F5 /* AccountIdCodingWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountIdCodingWrapper.swift; sourceTree = ""; }; 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFetchTests.swift; sourceTree = ""; }; 847A25C528D84BE2006AC9F5 /* Referenda.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Referenda.swift; sourceTree = ""; }; - 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Referenda+StorageCodingPath.swift"; sourceTree = ""; }; + 847A25C728D84C0A006AC9F5 /* Referenda+CodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Referenda+CodingPath.swift"; sourceTree = ""; }; 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumInfo.swift; sourceTree = ""; }; 847A6C0828817DC700477F77 /* AssetListBaseInteractorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListBaseInteractorProtocol.swift; sourceTree = ""; }; 847A6C0A28817E4000477F77 /* AssetListBaseInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListBaseInteractor.swift; sourceTree = ""; }; @@ -4296,6 +4301,9 @@ 849FA21528A26CB500F83EAA /* CountdownTimerMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountdownTimerMediator.swift; sourceTree = ""; }; 84A04621277DE83E000B24DA /* DAppListErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppListErrorView.swift; sourceTree = ""; }; 84A15488262888CA0050D557 /* IdentityOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityOperationFactory.swift; sourceTree = ""; }; + 84A1742328ED3CF70096F943 /* ReferendumLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLocal.swift; sourceTree = ""; }; + 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceOperationProtocols.swift; sourceTree = ""; }; + 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2OperationFactory.swift; sourceTree = ""; }; 84A2A60926B82B35000C6C6C /* ValidatorOperationFactory+Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ValidatorOperationFactory+Protocol.swift"; sourceTree = ""; }; 84A2C90124E07E440020D3B7 /* CryptoType+Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CryptoType+Utils.swift"; sourceTree = ""; }; 84A2C90324E07F400020D3B7 /* AccountOperationFactoryError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountOperationFactoryError.swift; sourceTree = ""; }; @@ -4495,6 +4503,8 @@ 84C3F77A2601F08B00D47501 /* NominationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NominationViewModel.swift; sourceTree = ""; }; 84C3F7822602086100D47501 /* StakingViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingViewState.swift; sourceTree = ""; }; 84C3F78B26020DE800D47501 /* StakingStateMachineProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingStateMachineProtocols.swift; sourceTree = ""; }; + 84C41F3528EDADE000DB1CD3 /* ReferendaTrackInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendaTrackInfo.swift; sourceTree = ""; }; + 84C41F3728EDB80700DB1CD3 /* ReferendaCurve.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendaCurve.swift; sourceTree = ""; }; 84C4C2D6255D2B780045B582 /* PinChangeWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinChangeWireframe.swift; sourceTree = ""; }; 84C4C2F8255DB9510045B582 /* PinChangeInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinChangeInteractor.swift; sourceTree = ""; }; 84C515FA26D84F8C000DBA45 /* AccountImportWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountImportWrapper.swift; sourceTree = ""; }; @@ -8239,6 +8249,7 @@ 847A25C028D84A3D006AC9F5 /* Governance */ = { isa = PBXGroup; children = ( + 84A1742528ED60610096F943 /* Operation */, 84D8753B28EB1796004065BD /* Model */, 8442002128E6FE0100C49C4A /* Referendums */, ); @@ -8249,9 +8260,11 @@ isa = PBXGroup; children = ( 847A25C528D84BE2006AC9F5 /* Referenda.swift */, - 847A25C728D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift */, + 847A25C728D84C0A006AC9F5 /* Referenda+CodingPath.swift */, 847A25C928D85204006AC9F5 /* ReferendumInfo.swift */, 848CC93E28D9F90D009EB4B0 /* ReferendaDeposit.swift */, + 84C41F3528EDADE000DB1CD3 /* ReferendaTrackInfo.swift */, + 84C41F3728EDB80700DB1CD3 /* ReferendaCurve.swift */, ); path = Referenda; sourceTree = ""; @@ -9735,6 +9748,15 @@ path = Model; sourceTree = ""; }; + 84A1742528ED60610096F943 /* Operation */ = { + isa = PBXGroup; + children = ( + 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */, + 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, + ); + path = Operation; + sourceTree = ""; + }; 84A2A60826B82B1C000C6C6C /* ValidatorOperationFactory */ = { isa = PBXGroup; children = ( @@ -10959,6 +10981,7 @@ isa = PBXGroup; children = ( 84D8753C28EB17B2004065BD /* GovernanceSharedState.swift */, + 84A1742328ED3CF70096F943 /* ReferendumLocal.swift */, ); path = Model; sourceTree = ""; @@ -13714,6 +13737,7 @@ 846802A3265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift in Sources */, 849014C324AA87E4008F705E /* LocalAuthInteractor.swift in Sources */, 84BEE059255F4D5700D05EB3 /* AccountImportPreferredInfo.swift in Sources */, + 84C41F3828EDB80700DB1CD3 /* ReferendaCurve.swift in Sources */, 8490141524A92F6D008F705E /* OnboardingMainPresenter.swift in Sources */, 846449FF2567090B004EAA4B /* TriangularedView+Inspectable.swift in Sources */, 8460E11D2542011200826F55 /* DetailsTriangularedView.swift in Sources */, @@ -13786,6 +13810,7 @@ 84DA3B1224C6D29100B5E27F /* RuntimeVersion.swift in Sources */, 8476D3A127F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift in Sources */, 8445F41628C8CFEC009E61C4 /* ParaStkYieldBoostSelectionViewModel.swift in Sources */, + 84A1742428ED3CF70096F943 /* ReferendumLocal.swift in Sources */, 843C49DB24DF373000B71DDA /* AccountImportRequest.swift in Sources */, 843910C1253F36F300E3C217 /* BaseStorageChildSubscription.swift in Sources */, 84FAB0812543A7EE00319F74 /* ReceiveConfigurator.swift in Sources */, @@ -14349,7 +14374,7 @@ 8463A72D25E3A8E1003B8160 /* ChainStorageDecodedItem.swift in Sources */, 84DD5F30263D84F300425ACF /* RuntimeConstantFetching.swift in Sources */, 84B64E412704569D00914E88 /* StakingLocalSubscriptionHandler.swift in Sources */, - 847A25C828D84C0A006AC9F5 /* Referenda+StorageCodingPath.swift in Sources */, + 847A25C828D84C0A006AC9F5 /* Referenda+CodingPath.swift in Sources */, 880855F428D09A26004255E7 /* RemoteCrowdloanContribution.swift in Sources */, 848FFE9525E6DF2200652AA5 /* PagedKeysRequest.swift in Sources */, 8428766B24ADF51D00D91AD8 /* UIViewController+Modal.swift in Sources */, @@ -14471,6 +14496,7 @@ 84DB9E902640A48E00F23DD3 /* StakingRedeemViewModel.swift in Sources */, 84D8F16124D8193200AF43E9 /* IconWithTitleTableViewCell.swift in Sources */, 844ADE7E28CB351500EE29F7 /* AutomationTimeAutocompound.swift in Sources */, + 84C41F3628EDADE000DB1CD3 /* ReferendaTrackInfo.swift in Sources */, AEF507F226259DF00098574D /* ValidationViewModel.swift in Sources */, 847F2D4827A9DDC700AFD476 /* MultigradientView+Default.swift in Sources */, 8448F7A6288314250080CEA9 /* AssetListAssetsViewModelFactory.swift in Sources */, @@ -14690,6 +14716,7 @@ 848F8B222863BD1000204BC4 /* TransferSetupInputState.swift in Sources */, 84113B6C255B2835009BD21A /* AccountCreateError.swift in Sources */, 849014C024AA87E4008F705E /* ScreenAuthorizationPresenter.swift in Sources */, + 84A1742928ED625D0096F943 /* Gov2OperationFactory.swift in Sources */, 84EC2D1D276C684D009B0BE1 /* PolkadotExtensionSignerResult.swift in Sources */, 84F5105B263AB9F2005D15AE /* NetworkFeeView.swift in Sources */, 84786E2425FBA2A50089DFF7 /* StakingAccountSubscription.swift in Sources */, @@ -16203,6 +16230,7 @@ E221892A5B6A41A944B88336 /* ParaStkYieldBoostStartProtocols.swift in Sources */, 8F131D86B269B7FAB96CF3B5 /* ParaStkYieldBoostStartWireframe.swift in Sources */, EEDDE41F8445C0CB2E99AFE4 /* ParaStkYieldBoostStartPresenter.swift in Sources */, + 84A1742728ED607B0096F943 /* GovernanceOperationProtocols.swift in Sources */, B6D4C073B3F984FE0348B7D4 /* ParaStkYieldBoostStartInteractor.swift in Sources */, 72EF67BA5380D1CDBB73E23F /* ParaStkYieldBoostStartViewController.swift in Sources */, DB20B86D7BDE3788947ED9A4 /* ParaStkYieldBoostStartViewLayout.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/Referenda/Referenda+StorageCodingPath.swift b/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift similarity index 58% rename from novawallet/Common/Substrate/Types/Referenda/Referenda+StorageCodingPath.swift rename to novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift index adf78477c0..1e6a365d12 100644 --- a/novawallet/Common/Substrate/Types/Referenda/Referenda+StorageCodingPath.swift +++ b/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift @@ -4,4 +4,8 @@ extension Referenda { static var referendumInfo: StorageCodingPath { StorageCodingPath(moduleName: "Referenda", itemName: "ReferendumInfoFor") } + + static var tracks: ConstantCodingPath { + ConstantCodingPath(moduleName: "Referenda", constantName: "Tracks") + } } diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendaCurve.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendaCurve.swift new file mode 100644 index 0000000000..115081316c --- /dev/null +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendaCurve.swift @@ -0,0 +1,50 @@ +import Foundation +import SubstrateSdk +import BigInt + +extension Referenda { + struct LinearDecreasingCurve: Decodable { + @StringCodable var length: BigUInt + @StringCodable var floor: BigUInt + @StringCodable var ceil: BigUInt + } + + struct SteppedDecreasingCurve: Decodable { + @StringCodable var begin: BigUInt + @StringCodable var end: BigUInt + @StringCodable var step: BigUInt + @StringCodable var period: BigUInt + } + + struct ReciprocalCurve: Decodable { + @StringCodable var factor: Int64 + @StringCodable var xOffset: Int64 + @StringCodable var yOffset: Int64 + } + + enum Curve: Decodable { + case linearDecreasing(_ params: LinearDecreasingCurve) + case steppedDecreasing(_ params: SteppedDecreasingCurve) + case reciprocal(_ params: ReciprocalCurve) + case unknown + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "LinearDecreasing": + let curve = try container.decode(LinearDecreasingCurve.self) + self = .linearDecreasing(curve) + case "SteppedDecreasing": + let curve = try container.decode(SteppedDecreasingCurve.self) + self = .steppedDecreasing(curve) + case "Reciprocal": + let curve = try container.decode(ReciprocalCurve.self) + self = .reciprocal(curve) + default: + self = .unknown + } + } + } +} diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendaTrackInfo.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendaTrackInfo.swift new file mode 100644 index 0000000000..dfbd2b894d --- /dev/null +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendaTrackInfo.swift @@ -0,0 +1,29 @@ +import Foundation +import SubstrateSdk +import BigInt + +extension Referenda { + struct TrackInfo: Decodable { + let name: String + @StringCodable var maxDeciding: UInt32 + @StringCodable var decisionDeposit: BigUInt + @StringCodable var preparePeriod: Moment + @StringCodable var decisionPeriod: Moment + @StringCodable var confirmPeriod: Moment + @StringCodable var minEnactmentPeriod: Moment + let minApproval: Referenda.Curve + let minSupport: Referenda.Curve + } + + struct Track: Decodable { + let trackId: Referenda.TrackId + let info: TrackInfo + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + + trackId = try container.decode(StringScaleMapper.self).value + info = try container.decode(TrackInfo.self) + } + } +} diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift index 6ae9b4973c..846f2347d5 100644 --- a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift @@ -12,18 +12,31 @@ enum ReferendumInfo: Decodable { @BytesCodable var proposalHash: Data let enactment: OnChainScheduler.DispatchTime @StringCodable var submitted: Moment + let submissionDeposit: Referenda.Deposit let decisionDeposit: Referenda.Deposit? let deciding: DecidingStatus? let tally: ConvictionVoting.Tally let inQueue: Bool } + struct CompletedStatus { + let since: Moment + let submissionDeposit: Referenda.Deposit + let decisionDeposit: Referenda.Deposit? + + init(container: inout UnkeyedDecodingContainer) throws { + since = try container.decode(StringScaleMapper.self).value + submissionDeposit = try container.decode(Referenda.Deposit.self) + decisionDeposit = try container.decodeIfPresent(Referenda.Deposit.self) + } + } + case ongoing(_ status: OngoingStatus) - case approved - case rejected - case cancelled - case timedOut - case killed + case approved(_ status: CompletedStatus) + case rejected(_ status: CompletedStatus) + case cancelled(_ status: CompletedStatus) + case timedOut(_ status: CompletedStatus) + case killed(_ atBlock: Moment) case unknown public init(from decoder: Decoder) throws { @@ -35,15 +48,20 @@ enum ReferendumInfo: Decodable { let status = try container.decode(OngoingStatus.self) self = .ongoing(status) case "Approved": - self = .approved + let status = try CompletedStatus(container: &container) + self = .approved(status) case "Rejected": - self = .rejected + let status = try CompletedStatus(container: &container) + self = .rejected(status) case "Cancelled": - self = .cancelled + let status = try CompletedStatus(container: &container) + self = .cancelled(status) case "TimedOut": - self = .timedOut + let status = try CompletedStatus(container: &container) + self = .timedOut(status) case "Killed": - self = .killed + let since = try container.decode(StringScaleMapper.self).value + self = .killed(since) default: self = .unknown } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift new file mode 100644 index 0000000000..b8b06fb558 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -0,0 +1,54 @@ +import Foundation +import BigInt + +struct ReferendumLocal { + let index: UInt + let state: ReferendumStateLocal +} + +struct SupportAndVotesLocal { + let ayes: BigUInt + let nays: BigUInt + let support: BigUInt +} + +enum ReferendumStateLocal { + enum Voting { + case supportAndVotes(model: SupportAndVotesLocal) + } + + struct Deciding { + let trackId: UInt16 + let voting: Voting + let since: BlockNumber + let period: Moment + let confirmationUntil: BlockNumber? + } + + struct Preparing { + let trackId: UInt16 + let voting: Voting + let deposit: BigUInt? + let since: BlockNumber + let period: Moment + let inQueue: Bool + } + + case preparing(model: Preparing) + case deciding(model: Deciding) + case approved(atBlock: Moment) + case rejected(atBlock: Moment) + case cancelled(atBlock: Moment) + case timedOut(atBlock: Moment) + case killed(atBlock: Moment) + case executed + + var completed: Bool { + switch self { + case .preparing, .deciding: + return false + case .approved, .rejected, .cancelled, .timedOut, .killed, .executed: + return true + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift new file mode 100644 index 0000000000..2a93fe591f --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -0,0 +1,121 @@ +import Foundation +import SubstrateSdk +import RobinHood + +final class Gov2OperationFactory { + let requestFactory: StorageRequestFactoryProtocol + + init(requestFactory: StorageRequestFactoryProtocol) { + self.requestFactory = requestFactory + } + + private func createReferendumMapOperation( + dependingOn remoteOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]> + ) -> BaseOperation<[ReferendumLocal]> { + ClosureOperation<[ReferendumLocal]> { + let remoteReferendums = try remoteOperation.extractNoCancellableResultData() + + return remoteReferendums.compactMap { keyedReferendum in + let referendumIndex = keyedReferendum.key.referendumIndex + let remoteReferendum = keyedReferendum.value + + switch remoteReferendum { + case let .ongoing(status): + let state: ReferendumStateLocal + + let votes = SupportAndVotesLocal( + ayes: status.tally.ayes, + nays: status.tally.nays, + support: status.tally.support + ) + + if let deciding = status.deciding { + let model = ReferendumStateLocal.Deciding( + trackId: status.track, + voting: .supportAndVotes(model: votes), + since: deciding.since, + period: 0, + confirmationUntil: deciding.confirming + ) + + state = .deciding(model: model) + } else { + let preparing = ReferendumStateLocal.Preparing( + trackId: status.track, + voting: .supportAndVotes(model: votes), + deposit: status.decisionDeposit?.amount, + since: status.submitted, + period: 0, + inQueue: status.inQueue + ) + + state = .preparing(model: preparing) + } + + return ReferendumLocal( + index: UInt(referendumIndex), + state: state + ) + case let .approved(status): + return ReferendumLocal( + index: UInt(referendumIndex), + state: .approved(atBlock: status.since) + ) + case let .rejected(status): + return ReferendumLocal( + index: UInt(referendumIndex), + state: .rejected(atBlock: status.since) + ) + case let .timedOut(status): + return ReferendumLocal( + index: UInt(referendumIndex), + state: .timedOut(atBlock: status.since) + ) + case let .cancelled(status): + return ReferendumLocal( + index: UInt(referendumIndex), + state: .cancelled(atBlock: status.since) + ) + case let .killed(atBlock): + return ReferendumLocal( + index: UInt(referendumIndex), + state: .killed(atBlock: atBlock) + ) + case .unknown: + return nil + } + } + } + } +} + +extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { + func fetchAllReferendumsWrapper( + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[ReferendumLocal]> { + let request = UnkeyedRemoteStorageRequest(storagePath: Referenda.referendumInfo) + + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let wrapper: CompoundOperationWrapper<[ReferendumIndexKey: ReferendumInfo]> = requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: request.storagePath, + factory: { + try codingFactoryOperation.extractNoCancellableResultData() + }, + at: nil + ) + + wrapper.addDependency(operations: [codingFactoryOperation]) + + let mapOperation = createReferendumMapOperation(dependingOn: wrapper.targetOperation) + + mapOperation.addDependency(wrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + wrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift new file mode 100644 index 0000000000..1e2e248f55 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -0,0 +1,10 @@ +import Foundation +import SubstrateSdk +import RobinHood + +protocol ReferendumsOperationFactoryProtocol { + func fetchAllReferendumsWrapper( + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[ReferendumLocal]> +} diff --git a/novawalletIntegrationTests/ReferendumFetchTests.swift b/novawalletIntegrationTests/ReferendumFetchTests.swift index c83d006c27..d4d6c051dc 100644 --- a/novawalletIntegrationTests/ReferendumFetchTests.swift +++ b/novawalletIntegrationTests/ReferendumFetchTests.swift @@ -57,4 +57,45 @@ class ReferendumFetchTests: XCTestCase { XCTFail("Unexpected error \(error)") } } + + func testFetchAllTracks() { + // given + + let storageFacade = SubstrateStorageTestFacade() + let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) + let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" + let operationQueue = OperationQueue() + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + XCTFail("Can't get runtime provider for chain id \(chainId)") + return + } + + // when + + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let constantOperation = StorageConstantOperation<[Referenda.Track]>(path: Referenda.tracks) + + constantOperation.configurationBlock = { + do { + constantOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + constantOperation.result = .failure(error) + } + } + + constantOperation.addDependency(codingFactoryOperation) + + operationQueue.addOperations([codingFactoryOperation, constantOperation], waitUntilFinished: true) + + // then + + do { + let tracks = try constantOperation.extractNoCancellableResultData() + Logger.shared.info("Tracks: \(tracks)") + } catch { + XCTFail("Unexpected error: \(error)") + } + } } From 2145298a61103f6ba9bf1c1320d9b87fdd0cda4a Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 6 Oct 2022 11:39:07 +0500 Subject: [PATCH 014/229] add threshold calculation logic --- Podfile | 4 +- Podfile.lock | 8 +- novawallet.xcodeproj/project.pbxproj | 8 ++ .../Foundation/Decimal+Conversion.swift | 13 ++++ .../Types/Referenda/ReferendaCurve.swift | 11 +++ .../Governance/Model/ReferendumLocal.swift | 9 ++- .../ReferendumLocalDecidingFunction.swift | 78 +++++++++++++++++++ .../Operation/Gov2LocalMappingFactory.swift | 74 ++++++++++++++++++ 8 files changed, 197 insertions(+), 8 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift diff --git a/Podfile b/Podfile index 3e3f144e3f..01104c05ea 100644 --- a/Podfile +++ b/Podfile @@ -4,7 +4,7 @@ platform :ios, '13.0' abstract_target 'novawalletAll' do use_frameworks! - pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :commit => '9063bd531492726097597e442db0f04cd2d8210d' + pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '1.4.1' pod 'SwiftLint' pod 'R.swift', :inhibit_warnings => true pod 'SoraKeystore', '~> 1.0.0' @@ -27,7 +27,7 @@ abstract_target 'novawalletAll' do inherit! :search_paths pod 'Cuckoo' - pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :commit => '9063bd531492726097597e442db0f04cd2d8210d' + pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '1.4.1' pod 'SoraFoundation', '~> 1.0.0' pod 'R.swift', :inhibit_warnings => true pod 'FireMock', :inhibit_warnings => true diff --git a/Podfile.lock b/Podfile.lock index f8a944997a..d0eec8b5d8 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -137,7 +137,7 @@ DEPENDENCIES: - SoraUI (from `https://github.com/ERussel/UIkit-iOS.git`, tag `1.11.1`) - Sourcery (~> 1.4) - Starscream (from `https://github.com/ERussel/Starscream.git`, tag `4.0.5`) - - SubstrateSdk (from `https://github.com/nova-wallet/substrate-sdk-ios.git`, commit `9063bd531492726097597e442db0f04cd2d8210d`) + - SubstrateSdk (from `https://github.com/nova-wallet/substrate-sdk-ios.git`, tag `1.4.1`) - SVGKit (from `https://github.com/SVGKit/SVGKit.git`, tag `3.0.0`) - SwiftFormat/CLI (~> 0.47.13) - SwiftLint @@ -181,8 +181,8 @@ EXTERNAL SOURCES: :git: https://github.com/ERussel/Starscream.git :tag: 4.0.5 SubstrateSdk: - :commit: 9063bd531492726097597e442db0f04cd2d8210d :git: https://github.com/nova-wallet/substrate-sdk-ios.git + :tag: 1.4.1 SVGKit: :git: https://github.com/SVGKit/SVGKit.git :tag: 3.0.0 @@ -200,8 +200,8 @@ CHECKOUT OPTIONS: :git: https://github.com/ERussel/Starscream.git :tag: 4.0.5 SubstrateSdk: - :commit: 9063bd531492726097597e442db0f04cd2d8210d :git: https://github.com/nova-wallet/substrate-sdk-ios.git + :tag: 1.4.1 SVGKit: :git: https://github.com/SVGKit/SVGKit.git :tag: 3.0.0 @@ -240,6 +240,6 @@ SPEC CHECKSUMS: TweetNacl: 3abf4d1d2082b0114e7a67410e300892448951e6 xxHash-Swift: 30bd6a7507b3b7348a277c49b1cb6346c2905ec7 -PODFILE CHECKSUM: 4e7796fb71944def78c45a246b810d31342cd2fa +PODFILE CHECKSUM: e7a9db8afc40a39eeb2135ca842e4b7931c5c709 COCOAPODS: 1.11.3 diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index cf46d0179d..dd63fe1458 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1880,6 +1880,8 @@ 84DC3CE52796768A0038E2ED /* SubqueryHistoryContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DC3CE42796768A0038E2ED /* SubqueryHistoryContext.swift */; }; 84DC3CE7279679230038E2ED /* SubqueryHistory+Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DC3CE6279679230038E2ED /* SubqueryHistory+Wallet.swift */; }; 84DC5A1328BAA8020014E081 /* LedgerInvaliDataPolkadotReason.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DC5A1228BAA8020014E081 /* LedgerInvaliDataPolkadotReason.swift */; }; + 84DD49F428EE91ED00B804F3 /* Gov2LocalMappingFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */; }; + 84DD49F628EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD49F528EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift */; }; 84DD5F21263CB6BE00425ACF /* UnbondCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD5F20263CB6BE00425ACF /* UnbondCall.swift */; }; 84DD5F26263D72C400425ACF /* ExtrinsicFeeProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD5F25263D72C400425ACF /* ExtrinsicFeeProxy.swift */; }; 84DD5F30263D84F300425ACF /* RuntimeConstantFetching.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD5F2F263D84F300425ACF /* RuntimeConstantFetching.swift */; }; @@ -4676,6 +4678,8 @@ 84DC3CE42796768A0038E2ED /* SubqueryHistoryContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubqueryHistoryContext.swift; sourceTree = ""; }; 84DC3CE6279679230038E2ED /* SubqueryHistory+Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubqueryHistory+Wallet.swift"; sourceTree = ""; }; 84DC5A1228BAA8020014E081 /* LedgerInvaliDataPolkadotReason.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LedgerInvaliDataPolkadotReason.swift; sourceTree = ""; }; + 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2LocalMappingFactory.swift; sourceTree = ""; }; + 84DD49F528EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLocalDecidingFunction.swift; sourceTree = ""; }; 84DD5F20263CB6BE00425ACF /* UnbondCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnbondCall.swift; sourceTree = ""; }; 84DD5F25263D72C400425ACF /* ExtrinsicFeeProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicFeeProxy.swift; sourceTree = ""; }; 84DD5F2F263D84F300425ACF /* RuntimeConstantFetching.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeConstantFetching.swift; sourceTree = ""; }; @@ -9753,6 +9757,7 @@ children = ( 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */, 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, + 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, ); path = Operation; sourceTree = ""; @@ -10982,6 +10987,7 @@ children = ( 84D8753C28EB17B2004065BD /* GovernanceSharedState.swift */, 84A1742328ED3CF70096F943 /* ReferendumLocal.swift */, + 84DD49F528EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift */, ); path = Model; sourceTree = ""; @@ -15280,6 +15286,7 @@ 8436E94426C853E4003D4EA7 /* RuntimeSnapshotOperationFactory.swift in Sources */, F40966C726B297D6008CD244 /* AnalyticsRewardsViewFactory.swift in Sources */, 846AF83E2525B85100868F37 /* WalletNetworkFacade.swift in Sources */, + 84DD49F428EE91ED00B804F3 /* Gov2LocalMappingFactory.swift in Sources */, 8489EDBA264DB25500FF997E /* RecommendationsComposing.swift in Sources */, F41CEB88272FFCB700C06154 /* CrowdloanContributionViewModel.swift in Sources */, 8466781327EC5446007935D3 /* MultilineBalanceView.swift in Sources */, @@ -16149,6 +16156,7 @@ 3AD7635AFA1F7E66A3C00F56 /* ParitySignerAddressesInteractor.swift in Sources */, 940DA38E4586A27D7F3E0C67 /* ParitySignerAddressesViewController.swift in Sources */, E8F04B9E557AD6BD0279EA6F /* ParitySignerAddressesViewLayout.swift in Sources */, + 84DD49F628EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift in Sources */, 01F973625B78736D5EEA86F6 /* ParitySignerAddressesViewFactory.swift in Sources */, ECD4EB7314609007CE35461E /* ParitySignerAddConfirmProtocols.swift in Sources */, 6D622CD4A83EEC1F135B66A8 /* ParitySignerAddConfirmWireframe.swift in Sources */, diff --git a/novawallet/Common/Extension/Foundation/Decimal+Conversion.swift b/novawallet/Common/Extension/Foundation/Decimal+Conversion.swift index d1c0266a6b..3b30f2b135 100644 --- a/novawallet/Common/Extension/Foundation/Decimal+Conversion.swift +++ b/novawallet/Common/Extension/Foundation/Decimal+Conversion.swift @@ -7,7 +7,20 @@ extension Decimal { return decimalValue.multiplying(byPowerOf10: -2).decimalValue } + static func fromFixedI64(value: Int64) -> Decimal { + Decimal(value) / 1_000_000_000 + } + init?(_ bigUInt: BigUInt) { self.init(string: String(bigUInt)) } + + func floor() -> Decimal { + var originValue = self + var rounded = Decimal() + + NSDecimalRound(&rounded, &originValue, 0, .down) + + return rounded + } } diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendaCurve.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendaCurve.swift index 115081316c..3ed197dc06 100644 --- a/novawallet/Common/Substrate/Types/Referenda/ReferendaCurve.swift +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendaCurve.swift @@ -3,12 +3,22 @@ import SubstrateSdk import BigInt extension Referenda { + /** + * Linear curve starting at `(0, ceil)`, proceeding linearly to `(length, floor)`, then + * remaining at `floor` until the end of the period. + */ struct LinearDecreasingCurve: Decodable { @StringCodable var length: BigUInt @StringCodable var floor: BigUInt @StringCodable var ceil: BigUInt } + /** + * Stepped curve, beginning at `(0, begin)`, then remaining constant for `period`, at which + * point it steps down to `(period, begin - step)`. It then remains constant for another + * `period` before stepping down to `(period * 2, begin - step * 2)`. This pattern continues + * but the `y` component has a lower limit of `end`. + */ struct SteppedDecreasingCurve: Decodable { @StringCodable var begin: BigUInt @StringCodable var end: BigUInt @@ -16,6 +26,7 @@ extension Referenda { @StringCodable var period: BigUInt } + /// A recipocal (`K/(x+S)+T`) curve: `factor` is `K` and `x_offset` is `S`, `y_offset` is `T`. struct ReciprocalCurve: Decodable { @StringCodable var factor: Int64 @StringCodable var xOffset: Int64 diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index b8b06fb558..d702679969 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -18,7 +18,7 @@ enum ReferendumStateLocal { } struct Deciding { - let trackId: UInt16 + let track: GovernanceTrackLocal let voting: Voting let since: BlockNumber let period: Moment @@ -26,7 +26,7 @@ enum ReferendumStateLocal { } struct Preparing { - let trackId: UInt16 + let track: GovernanceTrackLocal let voting: Voting let deposit: BigUInt? let since: BlockNumber @@ -52,3 +52,8 @@ enum ReferendumStateLocal { } } } + +struct GovernanceTrackLocal { + let trackId: UInt16 + let name: String +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift new file mode 100644 index 0000000000..b722be64b9 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift @@ -0,0 +1,78 @@ +import Foundation + +protocol ReferendumLocalDecidingFunction { + func calculateThreshold(for block: BlockNumber) -> Decimal? +} + +struct Gov2LocalDecidingFunction: ReferendumLocalDecidingFunction { + let curve: Referenda.Curve + let startBlock: BlockNumber + let period: Moment + + private func calculateLinearDecreasing(from xPoint: Decimal, params: Referenda.LinearDecreasingCurve) -> Decimal? { + guard + let length = Decimal.fromSubstratePerbill(value: params.length), + length > 0.0, + let ceil = Decimal.fromSubstratePerbill(value: params.ceil), + let floor = Decimal.fromSubstratePerbill(value: params.floor) else { + return nil + } + + return ceil - (ceil - floor) * min(xPoint, length) / length + } + + private func calculateReciprocal(from xPoint: Decimal, params: Referenda.ReciprocalCurve) -> Decimal? { + let factor = Decimal.fromFixedI64(value: params.factor) + let xOffset = Decimal.fromFixedI64(value: params.xOffset) + let yOffset = Decimal.fromFixedI64(value: params.yOffset) + + let xAdd = xPoint + xOffset + + guard xAdd > 0 else { + return nil + } + + return factor / xAdd + yOffset + } + + private func calculateSteppedDecreasing(from xPoint: Decimal, params: Referenda.SteppedDecreasingCurve) -> Decimal? { + guard + let begin = Decimal.fromSubstratePerbill(value: params.begin), + let end = Decimal.fromSubstratePerbill(value: params.end), + let period = Decimal.fromSubstratePerbill(value: params.period), + period > 0, + let step = Decimal.fromSubstratePerbill(value: params.step) else { + return nil + } + + let periodIndex = (xPoint / period).floor() + let yPoint = min(begin - periodIndex * step, begin) + + return max(yPoint, end) + } +} + +extension Gov2LocalDecidingFunction { + func calculateThreshold(for block: BlockNumber) -> Decimal? { + let xPoint: Decimal + + if block < startBlock { + xPoint = 0 + } else if block > startBlock + period { + xPoint = 1 + } else { + xPoint = Decimal(block - startBlock) / Decimal(period) + } + + switch curve { + case let .linearDecreasing(params): + return calculateLinearDecreasing(from: xPoint, params: params) + case let .reciprocal(params): + return calculateReciprocal(from: xPoint, params: params) + case let .steppedDecreasing(params): + return calculateSteppedDecreasing(from: xPoint, params: params) + case .unknown: + return nil + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift new file mode 100644 index 0000000000..8d88c655bb --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -0,0 +1,74 @@ +import Foundation + +final class Gov2LocalMappingFactory { + private func createOngoingReferendumState( + from status: ReferendumInfo.OngoingStatus, + index: Referenda.ReferendumIndex, + track: Referenda.TrackInfo + ) -> ReferendumLocal { + let state: ReferendumStateLocal + + let votes = SupportAndVotesLocal( + ayes: status.tally.ayes, + nays: status.tally.nays, + support: status.tally.support + ) + + let localTrack = GovernanceTrackLocal(trackId: status.track, name: track.name) + + if let deciding = status.deciding { + let model = ReferendumStateLocal.Deciding( + track: localTrack, + voting: .supportAndVotes(model: votes), + since: deciding.since, + period: track.decisionPeriod, + confirmationUntil: deciding.confirming + ) + + state = .deciding(model: model) + } else { + let preparing = ReferendumStateLocal.Preparing( + track: localTrack, + voting: .supportAndVotes(model: votes), + deposit: status.decisionDeposit?.amount, + since: status.submitted, + period: track.preparePeriod, + inQueue: status.inQueue + ) + + state = .preparing(model: preparing) + } + + return ReferendumLocal( + index: UInt(index), + state: state + ) + } + + func mapRemote( + referendum: ReferendumInfo, + index: Referenda.ReferendumIndex, + tracks: [Referenda.TrackId: Referenda.TrackInfo] + ) -> ReferendumLocal? { + switch referendum { + case let .ongoing(status): + guard let track = tracks[status.track] else { + return nil + } + + return createOngoingReferendumState(from: status, index: index, track: track) + case let .approved(status): + return ReferendumLocal(index: UInt(index), state: .approved(atBlock: status.since)) + case let .rejected(status): + return ReferendumLocal(index: UInt(index), state: .rejected(atBlock: status.since)) + case let .timedOut(status): + return ReferendumLocal(index: UInt(index), state: .timedOut(atBlock: status.since)) + case let .cancelled(status): + return ReferendumLocal(index: UInt(index), state: .cancelled(atBlock: status.since)) + case let .killed(atBlock): + return ReferendumLocal(index: UInt(index), state: .killed(atBlock: atBlock)) + case .unknown: + return nil + } + } +} From 3a26290bff89cfcd08d5c3bbbe633d4db70741cd Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 6 Oct 2022 17:05:48 +0500 Subject: [PATCH 015/229] fix completed status --- novawallet.xcodeproj/project.pbxproj | 8 + .../Referenda/Referenda+CodingPath.swift | 4 + .../Types/Referenda/ReferendumInfo.swift | 24 +-- .../Governance/Model/ReferendumLocal.swift | 40 +++- .../ReferendumLocalDecidingFunction.swift | 5 +- .../Operation/Gov2LocalMappingFactory.swift | 116 ++++++++---- .../Operation/Gov2OperationFactory.swift | 175 ++++++++++-------- .../Gov2OperationFactoryTests.swift | 50 +++++ .../Common/Extensions/DecimalTests.swift | 21 +++ 9 files changed, 316 insertions(+), 127 deletions(-) create mode 100644 novawalletIntegrationTests/Gov2OperationFactoryTests.swift create mode 100644 novawalletTests/Common/Extensions/DecimalTests.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index dd63fe1458..f9a6a9c30d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -712,6 +712,7 @@ 843A2C7326A8641400266F53 /* MultiValueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843A2C7226A8641400266F53 /* MultiValueView.swift */; }; 843A2C7726A86FD000266F53 /* TitleStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843A2C7626A86FD000266F53 /* TitleStatusView.swift */; }; 843B1D7A263EED5C00AF8957 /* StakingUnbondConfirmLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843B1D79263EED5C00AF8957 /* StakingUnbondConfirmLayout.swift */; }; + 843B6F4F28EEEF610086D4E0 /* Gov2OperationFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843B6F4E28EEEF610086D4E0 /* Gov2OperationFactoryTests.swift */; }; 843C49D824DD98CC00B71DDA /* DerivationPathConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843C49D724DD98CC00B71DDA /* DerivationPathConstants.swift */; }; 843C49DB24DF373000B71DDA /* AccountImportRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843C49DA24DF373000B71DDA /* AccountImportRequest.swift */; }; 843C49DF24DF3CB300B71DDA /* AccountImportMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843C49DE24DF3CB300B71DDA /* AccountImportMetadata.swift */; }; @@ -1882,6 +1883,7 @@ 84DC5A1328BAA8020014E081 /* LedgerInvaliDataPolkadotReason.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DC5A1228BAA8020014E081 /* LedgerInvaliDataPolkadotReason.swift */; }; 84DD49F428EE91ED00B804F3 /* Gov2LocalMappingFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */; }; 84DD49F628EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD49F528EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift */; }; + 84DD49F828EEAFFF00B804F3 /* DecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD49F728EEAFFF00B804F3 /* DecimalTests.swift */; }; 84DD5F21263CB6BE00425ACF /* UnbondCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD5F20263CB6BE00425ACF /* UnbondCall.swift */; }; 84DD5F26263D72C400425ACF /* ExtrinsicFeeProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD5F25263D72C400425ACF /* ExtrinsicFeeProxy.swift */; }; 84DD5F30263D84F300425ACF /* RuntimeConstantFetching.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD5F2F263D84F300425ACF /* RuntimeConstantFetching.swift */; }; @@ -3496,6 +3498,7 @@ 843A2C7226A8641400266F53 /* MultiValueView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiValueView.swift; sourceTree = ""; }; 843A2C7626A86FD000266F53 /* TitleStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleStatusView.swift; sourceTree = ""; }; 843B1D79263EED5C00AF8957 /* StakingUnbondConfirmLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingUnbondConfirmLayout.swift; sourceTree = ""; }; + 843B6F4E28EEEF610086D4E0 /* Gov2OperationFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2OperationFactoryTests.swift; sourceTree = ""; }; 843C49D724DD98CC00B71DDA /* DerivationPathConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DerivationPathConstants.swift; sourceTree = ""; }; 843C49DA24DF373000B71DDA /* AccountImportRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountImportRequest.swift; sourceTree = ""; }; 843C49DE24DF3CB300B71DDA /* AccountImportMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountImportMetadata.swift; sourceTree = ""; }; @@ -4680,6 +4683,7 @@ 84DC5A1228BAA8020014E081 /* LedgerInvaliDataPolkadotReason.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LedgerInvaliDataPolkadotReason.swift; sourceTree = ""; }; 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2LocalMappingFactory.swift; sourceTree = ""; }; 84DD49F528EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLocalDecidingFunction.swift; sourceTree = ""; }; + 84DD49F728EEAFFF00B804F3 /* DecimalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecimalTests.swift; sourceTree = ""; }; 84DD5F20263CB6BE00425ACF /* UnbondCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnbondCall.swift; sourceTree = ""; }; 84DD5F25263D72C400425ACF /* ExtrinsicFeeProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicFeeProxy.swift; sourceTree = ""; }; 84DD5F2F263D84F300425ACF /* RuntimeConstantFetching.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeConstantFetching.swift; sourceTree = ""; }; @@ -7145,6 +7149,7 @@ 84BFE8A128C2420A00140F1F /* AutocompounDelegateStakeTests.swift */, 847A25C228D84A9C006AC9F5 /* ReferendumFetchTests.swift */, 84532D5E28E4210E00EF4ADC /* ConvictionVotesFetchTests.swift */, + 843B6F4E28EEEF610086D4E0 /* Gov2OperationFactoryTests.swift */, ); path = novawalletIntegrationTests; sourceTree = ""; @@ -8367,6 +8372,7 @@ children = ( 84893BFB24D9B0F1008F6A3F /* PredicateTests.swift */, 846A2C53252A0FDF00731018 /* FilterTests.swift */, + 84DD49F728EEAFFF00B804F3 /* DecimalTests.swift */, ); path = Extensions; sourceTree = ""; @@ -13705,6 +13711,7 @@ AEE4E37225ECF83F00D6DF31 /* StakingInfoTests.swift in Sources */, E2F3E726280823CF00CF31B5 /* ETHAccountInjection.swift in Sources */, F441BE13263986BE0096B67B /* ExtrinsicServiceTests.swift in Sources */, + 843B6F4F28EEEF610086D4E0 /* Gov2OperationFactoryTests.swift in Sources */, 84FACB7125F57E4400F32ED4 /* SubstrateStorageTestFacade.swift in Sources */, 8418167728253B120007684A /* ParachainStakingCollatorsTests.swift in Sources */, 84F3B27E27F4206B00D64CF5 /* PhishingSitesSyncIntegrationTests.swift in Sources */, @@ -16366,6 +16373,7 @@ 8400F0BA252BBD2200E6B4CB /* WalletCommandFactoryProtocolMock.swift in Sources */, 84B7C729289BFA79001A3566 /* StartSelectValidatorsTests.swift in Sources */, 84B7C737289BFA79001A3566 /* StakingBondMoreTests.swift in Sources */, + 84DD49F828EEAFFF00B804F3 /* DecimalTests.swift in Sources */, F477CD75262FFA4F004DF739 /* PayoutRewardsServiceStub.swift in Sources */, 84B7C710289BFA79001A3566 /* CrowdloanYourContributionsTests.swift in Sources */, 8476D39827F431D5004D9A7A /* MockApplicationService.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift b/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift index 1e6a365d12..6a61391fd1 100644 --- a/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift +++ b/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift @@ -8,4 +8,8 @@ extension Referenda { static var tracks: ConstantCodingPath { ConstantCodingPath(moduleName: "Referenda", constantName: "Tracks") } + + static var undecidingTimeout: ConstantCodingPath { + ConstantCodingPath(moduleName: "Referenda", constantName: "UndecidingTimeout") + } } diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift index 846f2347d5..f1145b0251 100644 --- a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift @@ -19,16 +19,16 @@ enum ReferendumInfo: Decodable { let inQueue: Bool } - struct CompletedStatus { - let since: Moment + struct CompletedStatus: Decodable { + enum CodingKeys: String, CodingKey { + case since = "0" + case submissionDeposit = "1" + case decisionDeposit = "2" + } + + @StringCodable var since: Moment let submissionDeposit: Referenda.Deposit let decisionDeposit: Referenda.Deposit? - - init(container: inout UnkeyedDecodingContainer) throws { - since = try container.decode(StringScaleMapper.self).value - submissionDeposit = try container.decode(Referenda.Deposit.self) - decisionDeposit = try container.decodeIfPresent(Referenda.Deposit.self) - } } case ongoing(_ status: OngoingStatus) @@ -48,16 +48,16 @@ enum ReferendumInfo: Decodable { let status = try container.decode(OngoingStatus.self) self = .ongoing(status) case "Approved": - let status = try CompletedStatus(container: &container) + let status = try container.decode(CompletedStatus.self) self = .approved(status) case "Rejected": - let status = try CompletedStatus(container: &container) + let status = try container.decode(CompletedStatus.self) self = .rejected(status) case "Cancelled": - let status = try CompletedStatus(container: &container) + let status = try container.decode(CompletedStatus.self) self = .cancelled(status) case "TimedOut": - let status = try CompletedStatus(container: &container) + let status = try container.decode(CompletedStatus.self) self = .timedOut(status) case "Killed": let since = try container.decode(StringScaleMapper.self).value diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index d702679969..d56943e33f 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -10,6 +10,43 @@ struct SupportAndVotesLocal { let ayes: BigUInt let nays: BigUInt let support: BigUInt + let totalIssuance: BigUInt + + /// fraction of ayes + var approvalFraction: Decimal { + guard + let total = Decimal(ayes + nays), total > 0, + let ayesDecimal = Decimal(ayes) else { + return 0.0 + } + + return ayesDecimal / total + } + + /// fraction of voted tokens + var supportFraction: Decimal { + guard + let totalDecimal = Decimal(totalIssuance), totalDecimal > 0, + let supportDecimal = Decimal(support) else { + return 0.0 + } + + return supportDecimal / totalDecimal + } + + /// nil if not deciding yet + let approvalFunction: ReferendumLocalDecidingFunction? + let supportFunction: ReferendumLocalDecidingFunction? + + func isPassing(at block: BlockNumber) -> Bool { + guard + let approvalThreshold = approvalFunction?.calculateThreshold(for: block), + let supportThreshold = supportFunction?.calculateThreshold(for: block) else { + return false + } + + return approvalFraction >= approvalThreshold && supportFraction >= supportThreshold + } } enum ReferendumStateLocal { @@ -30,7 +67,8 @@ enum ReferendumStateLocal { let voting: Voting let deposit: BigUInt? let since: BlockNumber - let period: Moment + let preparingPeriod: Moment + let timeoutPeriod: Moment let inQueue: Bool } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift index b722be64b9..dc1a6d4909 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift @@ -35,7 +35,10 @@ struct Gov2LocalDecidingFunction: ReferendumLocalDecidingFunction { return factor / xAdd + yOffset } - private func calculateSteppedDecreasing(from xPoint: Decimal, params: Referenda.SteppedDecreasingCurve) -> Decimal? { + private func calculateSteppedDecreasing( + from xPoint: Decimal, + params: Referenda.SteppedDecreasingCurve + ) -> Decimal? { guard let begin = Decimal.fromSubstratePerbill(value: params.begin), let end = Decimal.fromSubstratePerbill(value: params.end), diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index 8d88c655bb..b28c6f7427 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -1,62 +1,112 @@ import Foundation final class Gov2LocalMappingFactory { - private func createOngoingReferendumState( + private func createDecidingState( from status: ReferendumInfo.OngoingStatus, - index: Referenda.ReferendumIndex, - track: Referenda.TrackInfo - ) -> ReferendumLocal { - let state: ReferendumStateLocal + deciding: ReferendumInfo.DecidingStatus, + track: Referenda.TrackInfo, + additionalInfo: Gov2OperationFactory.AdditionalInfo + ) -> ReferendumStateLocal { + let approvalFunction = Gov2LocalDecidingFunction( + curve: track.minApproval, + startBlock: deciding.since, + period: track.decisionPeriod + ) + + let supportFunction = Gov2LocalDecidingFunction( + curve: track.minSupport, + startBlock: deciding.since, + period: track.decisionPeriod + ) + + let votes = SupportAndVotesLocal( + ayes: status.tally.ayes, + nays: status.tally.nays, + support: status.tally.support, + totalIssuance: additionalInfo.totalIssuance, + approvalFunction: approvalFunction, + supportFunction: supportFunction + ) + let localTrack = GovernanceTrackLocal(trackId: status.track, name: track.name) + + let model = ReferendumStateLocal.Deciding( + track: localTrack, + voting: .supportAndVotes(model: votes), + since: deciding.since, + period: track.decisionPeriod, + confirmationUntil: deciding.confirming + ) + + return .deciding(model: model) + } + + private func createPreparingState( + from status: ReferendumInfo.OngoingStatus, + track: Referenda.TrackInfo, + additionalInfo: Gov2OperationFactory.AdditionalInfo + ) -> ReferendumStateLocal { let votes = SupportAndVotesLocal( ayes: status.tally.ayes, nays: status.tally.nays, - support: status.tally.support + support: status.tally.support, + totalIssuance: additionalInfo.totalIssuance, + approvalFunction: nil, + supportFunction: nil ) let localTrack = GovernanceTrackLocal(trackId: status.track, name: track.name) + let preparing = ReferendumStateLocal.Preparing( + track: localTrack, + voting: .supportAndVotes(model: votes), + deposit: status.decisionDeposit?.amount, + since: status.submitted, + preparingPeriod: track.preparePeriod, + timeoutPeriod: additionalInfo.undecidingTimeout, + inQueue: status.inQueue + ) + + return .preparing(model: preparing) + } + + private func createOngoingReferendumState( + from status: ReferendumInfo.OngoingStatus, + index: Referenda.ReferendumIndex, + additionalInfo: Gov2OperationFactory.AdditionalInfo + ) -> ReferendumLocal? { + guard let track = additionalInfo.tracks[status.track] else { + return nil + } + + let state: ReferendumStateLocal + if let deciding = status.deciding { - let model = ReferendumStateLocal.Deciding( - track: localTrack, - voting: .supportAndVotes(model: votes), - since: deciding.since, - period: track.decisionPeriod, - confirmationUntil: deciding.confirming + state = createDecidingState( + from: status, + deciding: deciding, + track: track, + additionalInfo: additionalInfo ) - - state = .deciding(model: model) } else { - let preparing = ReferendumStateLocal.Preparing( - track: localTrack, - voting: .supportAndVotes(model: votes), - deposit: status.decisionDeposit?.amount, - since: status.submitted, - period: track.preparePeriod, - inQueue: status.inQueue + state = createPreparingState( + from: status, + track: track, + additionalInfo: additionalInfo ) - - state = .preparing(model: preparing) } - return ReferendumLocal( - index: UInt(index), - state: state - ) + return ReferendumLocal(index: UInt(index), state: state) } func mapRemote( referendum: ReferendumInfo, index: Referenda.ReferendumIndex, - tracks: [Referenda.TrackId: Referenda.TrackInfo] + additionalInfo: Gov2OperationFactory.AdditionalInfo ) -> ReferendumLocal? { switch referendum { case let .ongoing(status): - guard let track = tracks[status.track] else { - return nil - } - - return createOngoingReferendumState(from: status, index: index, track: track) + return createOngoingReferendumState(from: status, index: index, additionalInfo: additionalInfo) case let .approved(status): return ReferendumLocal(index: UInt(index), state: .approved(atBlock: status.since)) case let .rejected(status): diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 2a93fe591f..c4cc3caa89 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -1,8 +1,15 @@ import Foundation import SubstrateSdk import RobinHood +import BigInt final class Gov2OperationFactory { + struct AdditionalInfo { + let tracks: [Referenda.TrackId: Referenda.TrackInfo] + let totalIssuance: BigUInt + let undecidingTimeout: Moment + } + let requestFactory: StorageRequestFactoryProtocol init(requestFactory: StorageRequestFactoryProtocol) { @@ -10,83 +17,86 @@ final class Gov2OperationFactory { } private func createReferendumMapOperation( - dependingOn remoteOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]> + dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, + additionalInfoOperation: BaseOperation ) -> BaseOperation<[ReferendumLocal]> { ClosureOperation<[ReferendumLocal]> { - let remoteReferendums = try remoteOperation.extractNoCancellableResultData() + let remoteReferendums = try referendumOperation.extractNoCancellableResultData() + let additionalInfo = try additionalInfoOperation.extractNoCancellableResultData() + + let mappingFactory = Gov2LocalMappingFactory() return remoteReferendums.compactMap { keyedReferendum in let referendumIndex = keyedReferendum.key.referendumIndex let remoteReferendum = keyedReferendum.value - switch remoteReferendum { - case let .ongoing(status): - let state: ReferendumStateLocal - - let votes = SupportAndVotesLocal( - ayes: status.tally.ayes, - nays: status.tally.nays, - support: status.tally.support - ) - - if let deciding = status.deciding { - let model = ReferendumStateLocal.Deciding( - trackId: status.track, - voting: .supportAndVotes(model: votes), - since: deciding.since, - period: 0, - confirmationUntil: deciding.confirming - ) - - state = .deciding(model: model) - } else { - let preparing = ReferendumStateLocal.Preparing( - trackId: status.track, - voting: .supportAndVotes(model: votes), - deposit: status.decisionDeposit?.amount, - since: status.submitted, - period: 0, - inQueue: status.inQueue - ) - - state = .preparing(model: preparing) - } - - return ReferendumLocal( - index: UInt(referendumIndex), - state: state - ) - case let .approved(status): - return ReferendumLocal( - index: UInt(referendumIndex), - state: .approved(atBlock: status.since) - ) - case let .rejected(status): - return ReferendumLocal( - index: UInt(referendumIndex), - state: .rejected(atBlock: status.since) - ) - case let .timedOut(status): - return ReferendumLocal( - index: UInt(referendumIndex), - state: .timedOut(atBlock: status.since) - ) - case let .cancelled(status): - return ReferendumLocal( - index: UInt(referendumIndex), - state: .cancelled(atBlock: status.since) - ) - case let .killed(atBlock): - return ReferendumLocal( - index: UInt(referendumIndex), - state: .killed(atBlock: atBlock) - ) - case .unknown: - return nil - } + return mappingFactory.mapRemote( + referendum: remoteReferendum, + index: referendumIndex, + additionalInfo: additionalInfo + ) } } } + + private func createAdditionalInfoWrapper( + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let tracksOperation = StorageConstantOperation<[Referenda.Track]>(path: Referenda.tracks) + + tracksOperation.configurationBlock = { + do { + tracksOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + tracksOperation.result = .failure(error) + } + } + + let undecidingTimeoutOperation = PrimitiveConstantOperation(path: Referenda.undecidingTimeout) + + undecidingTimeoutOperation.configurationBlock = { + do { + undecidingTimeoutOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + undecidingTimeoutOperation.result = .failure(error) + } + } + + let totalIssuanceWrapper: CompoundOperationWrapper>> = + requestFactory.queryItem( + engine: connection, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: .totalIssuance + ) + + let fetchOperations = [tracksOperation, undecidingTimeoutOperation] + totalIssuanceWrapper.allOperations + fetchOperations.forEach { $0.addDependency(codingFactoryOperation) } + + let mappingOperation = ClosureOperation { + let tracks = try tracksOperation.extractNoCancellableResultData().reduce( + into: [Referenda.TrackId: Referenda.TrackInfo]() + ) { $0[$1.trackId] = $1.info } + + let undecidingTimeout = try undecidingTimeoutOperation.extractNoCancellableResultData() + + let totalIssuance = try totalIssuanceWrapper.targetOperation.extractNoCancellableResultData().value + + return AdditionalInfo( + tracks: tracks, + totalIssuance: totalIssuance?.value ?? 0, + undecidingTimeout: undecidingTimeout + ) + } + + let dependencies = [codingFactoryOperation] + fetchOperations + + fetchOperations.forEach { mappingOperation.addDependency($0) } + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } } extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { @@ -98,23 +108,28 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - let wrapper: CompoundOperationWrapper<[ReferendumIndexKey: ReferendumInfo]> = requestFactory.queryByPrefix( - engine: connection, - request: request, - storagePath: request.storagePath, - factory: { - try codingFactoryOperation.extractNoCancellableResultData() - }, - at: nil - ) + let referendumWrapper: CompoundOperationWrapper<[ReferendumIndexKey: ReferendumInfo]> = + requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: request.storagePath, + factory: { try codingFactoryOperation.extractNoCancellableResultData() } + ) + + referendumWrapper.addDependency(operations: [codingFactoryOperation]) - wrapper.addDependency(operations: [codingFactoryOperation]) + let additionalInfoWrapper = createAdditionalInfoWrapper(from: connection, runtimeProvider: runtimeProvider) - let mapOperation = createReferendumMapOperation(dependingOn: wrapper.targetOperation) + let mapOperation = createReferendumMapOperation( + dependingOn: referendumWrapper.targetOperation, + additionalInfoOperation: additionalInfoWrapper.targetOperation + ) - mapOperation.addDependency(wrapper.targetOperation) + mapOperation.addDependency(referendumWrapper.targetOperation) + mapOperation.addDependency(additionalInfoWrapper.targetOperation) - let dependencies = [codingFactoryOperation] + wrapper.allOperations + let dependencies = [codingFactoryOperation] + referendumWrapper.allOperations + + additionalInfoWrapper.allOperations return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } diff --git a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift new file mode 100644 index 0000000000..063b930180 --- /dev/null +++ b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift @@ -0,0 +1,50 @@ +import XCTest +@testable import novawallet +import SubstrateSdk +import RobinHood + +class Gov2OperationFactoryTests: XCTestCase { + func testLocalReferendumsFetch() { + // given + + let storageFacade = SubstrateStorageTestFacade() + let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) + let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" + let operationQueue = OperationQueue() + + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + guard let connection = chainRegistry.getConnection(for: chainId) else { + XCTFail("Can't get connection for chain id \(chainId)") + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + XCTFail("Can't get runtime provider for chain id \(chainId)") + return + } + + // when + + let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) + + let wrapper = operationFactory.fetchAllReferendumsWrapper( + from: connection, + runtimeProvider: runtimeProvider + ) + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: true) + + // then + + do { + let referendums = try wrapper.targetOperation.extractNoCancellableResultData() + Logger.shared.info("Referendums: \(referendums)") + } catch { + XCTFail("Unexpected error: \(error)") + } + } +} diff --git a/novawalletTests/Common/Extensions/DecimalTests.swift b/novawalletTests/Common/Extensions/DecimalTests.swift new file mode 100644 index 0000000000..2158aedb66 --- /dev/null +++ b/novawalletTests/Common/Extensions/DecimalTests.swift @@ -0,0 +1,21 @@ +import XCTest +@testable import novawallet + +class DecimalTests: XCTestCase { + + func testDecimalFloor() { + XCTAssertEqual(Decimal(0.1).floor(), 0.0) + XCTAssertEqual(Decimal(0.5).floor(), 0.0) + XCTAssertEqual(Decimal(0.9).floor(), 0.0) + XCTAssertEqual(Decimal(5.1).floor(), 5.0) + XCTAssertEqual(Decimal(5.5).floor(), 5.0) + XCTAssertEqual(Decimal(5.9).floor(), 5.0) + + XCTAssertEqual(Decimal(-0.1).floor(), -1.0) + XCTAssertEqual(Decimal(-0.5).floor(), -1.0) + XCTAssertEqual(Decimal(-0.9).floor(), -1.0) + XCTAssertEqual(Decimal(-5.1).floor(), -6.0) + XCTAssertEqual(Decimal(-5.5).floor(), -6.0) + XCTAssertEqual(Decimal(-5.9).floor(), -6.0) + } +} From 036daaace18c0e12038829fa973f97ec71bd50b1 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 6 Oct 2022 18:31:02 +0500 Subject: [PATCH 016/229] add enactment time fetch --- .../Types/Scheduler/OnChainScheduler.swift | 16 +++- .../Governance/Model/ReferendumLocal.swift | 7 +- .../Operation/Gov2LocalMappingFactory.swift | 6 +- .../Operation/Gov2OperationFactory.swift | 87 ++++++++++++++++++- 4 files changed, 108 insertions(+), 8 deletions(-) diff --git a/novawallet/Common/Substrate/Types/Scheduler/OnChainScheduler.swift b/novawallet/Common/Substrate/Types/Scheduler/OnChainScheduler.swift index ae238cf604..41296ffaa7 100644 --- a/novawallet/Common/Substrate/Types/Scheduler/OnChainScheduler.swift +++ b/novawallet/Common/Substrate/Types/Scheduler/OnChainScheduler.swift @@ -1,3 +1,17 @@ import Foundation +import SubstrateSdk -enum OnChainScheduler {} +enum OnChainScheduler { + static var lookupTaskPath: StorageCodingPath { + StorageCodingPath(moduleName: "Scheduler", itemName: "Lookup") + } + + struct TaskAddress: Decodable { + let when: BlockNumber + + init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + when = try container.decode(StringScaleMapper.self).value + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index d56943e33f..15eef74110 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -72,9 +72,14 @@ enum ReferendumStateLocal { let inQueue: Bool } + struct Approved { + let since: BlockNumber + let whenEnactment: BlockNumber? + } + case preparing(model: Preparing) case deciding(model: Deciding) - case approved(atBlock: Moment) + case approved(model: Approved) case rejected(atBlock: Moment) case cancelled(atBlock: Moment) case timedOut(atBlock: Moment) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index b28c6f7427..d573dfdbdb 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -102,13 +102,15 @@ final class Gov2LocalMappingFactory { func mapRemote( referendum: ReferendumInfo, index: Referenda.ReferendumIndex, - additionalInfo: Gov2OperationFactory.AdditionalInfo + additionalInfo: Gov2OperationFactory.AdditionalInfo, + enactmentBlock: BlockNumber? ) -> ReferendumLocal? { switch referendum { case let .ongoing(status): return createOngoingReferendumState(from: status, index: index, additionalInfo: additionalInfo) case let .approved(status): - return ReferendumLocal(index: UInt(index), state: .approved(atBlock: status.since)) + let model = ReferendumStateLocal.Approved(since: status.since, whenEnactment: enactmentBlock) + return ReferendumLocal(index: UInt(index), state: .approved(model: model)) case let .rejected(status): return ReferendumLocal(index: UInt(index), state: .rejected(atBlock: status.since)) case let .timedOut(status): diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index c4cc3caa89..26a99fb8bf 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -10,19 +10,87 @@ final class Gov2OperationFactory { let undecidingTimeout: Moment } + struct SchedulerTaskName: Encodable { + let index: Referenda.ReferendumIndex + + func encode(to encoder: Encoder) throws { + let scaleEncoder = ScaleEncoder() + "assembly".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } + "enactment".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } + try index.encode(scaleEncoder: scaleEncoder) + + let data = try scaleEncoder.encode().blake2b32() + + var container = encoder.singleValueContainer() + try container.encode(BytesCodable(wrappedValue: data)) + } + } + let requestFactory: StorageRequestFactoryProtocol init(requestFactory: StorageRequestFactoryProtocol) { self.requestFactory = requestFactory } + private func createEnacmentTimeFetchWrapper( + dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[Referenda.ReferendumIndex: BlockNumber]> { + let keysClosure: () throws -> [SchedulerTaskName] = { + let referendums = try referendumOperation.extractNoCancellableResultData() + + return referendums.compactMap { keyValue in + switch keyValue.value { + case .approved: + return SchedulerTaskName(index: keyValue.key.referendumIndex) + default: + return nil + } + } + } + + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let enactmentWrapper: CompoundOperationWrapper<[StorageResponse]> = + requestFactory.queryItems( + engine: connection, + keyParams: keysClosure, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: OnChainScheduler.lookupTaskPath + ) + + enactmentWrapper.addDependency(operations: [codingFactoryOperation]) + + let mapOperation = ClosureOperation<[Referenda.ReferendumIndex: BlockNumber]> { + let keys = try keysClosure() + let results = try enactmentWrapper.targetOperation.extractNoCancellableResultData() + + return zip(keys, results).reduce(into: [Referenda.ReferendumIndex: BlockNumber]()) { accum, keyResult in + guard let when = keyResult.1.value?.when else { + return + } + + accum[keyResult.0.index] = when + } + } + + mapOperation.addDependency(enactmentWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + enactmentWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } + private func createReferendumMapOperation( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, - additionalInfoOperation: BaseOperation + additionalInfoOperation: BaseOperation, + enactmentsOperation: BaseOperation<[Referenda.ReferendumIndex: BlockNumber]> ) -> BaseOperation<[ReferendumLocal]> { ClosureOperation<[ReferendumLocal]> { let remoteReferendums = try referendumOperation.extractNoCancellableResultData() let additionalInfo = try additionalInfoOperation.extractNoCancellableResultData() + let enactments = try enactmentsOperation.extractNoCancellableResultData() let mappingFactory = Gov2LocalMappingFactory() @@ -33,7 +101,8 @@ final class Gov2OperationFactory { return mappingFactory.mapRemote( referendum: remoteReferendum, index: referendumIndex, - additionalInfo: additionalInfo + additionalInfo: additionalInfo, + enactmentBlock: enactments[referendumIndex] ) } } @@ -120,16 +189,26 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { let additionalInfoWrapper = createAdditionalInfoWrapper(from: connection, runtimeProvider: runtimeProvider) + let enactmentsWrapper = createEnacmentTimeFetchWrapper( + dependingOn: referendumWrapper.targetOperation, + connection: connection, + runtimeProvider: runtimeProvider + ) + + enactmentsWrapper.addDependency(wrapper: referendumWrapper) + let mapOperation = createReferendumMapOperation( dependingOn: referendumWrapper.targetOperation, - additionalInfoOperation: additionalInfoWrapper.targetOperation + additionalInfoOperation: additionalInfoWrapper.targetOperation, + enactmentsOperation: enactmentsWrapper.targetOperation ) mapOperation.addDependency(referendumWrapper.targetOperation) mapOperation.addDependency(additionalInfoWrapper.targetOperation) + mapOperation.addDependency(enactmentsWrapper.targetOperation) let dependencies = [codingFactoryOperation] + referendumWrapper.allOperations + - additionalInfoWrapper.allOperations + additionalInfoWrapper.allOperations + enactmentsWrapper.allOperations return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } From b92d1476b5a1837331c571744b8be9bdd4a086cd Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 6 Oct 2022 19:06:33 +0500 Subject: [PATCH 017/229] fix scheduler keys --- novawallet/Common/Substrate/Types/Referenda/Referenda.swift | 2 +- .../Vote/Governance/Operation/Gov2OperationFactory.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/novawallet/Common/Substrate/Types/Referenda/Referenda.swift b/novawallet/Common/Substrate/Types/Referenda/Referenda.swift index c049673666..fabeba5f91 100644 --- a/novawallet/Common/Substrate/Types/Referenda/Referenda.swift +++ b/novawallet/Common/Substrate/Types/Referenda/Referenda.swift @@ -2,5 +2,5 @@ import Foundation enum Referenda { typealias TrackId = UInt16 - typealias ReferendumIndex = UInt64 + typealias ReferendumIndex = UInt32 } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 26a99fb8bf..af0f181613 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -16,10 +16,10 @@ final class Gov2OperationFactory { func encode(to encoder: Encoder) throws { let scaleEncoder = ScaleEncoder() "assembly".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } - "enactment".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } + try "enactment".encode(scaleEncoder: scaleEncoder) try index.encode(scaleEncoder: scaleEncoder) - let data = try scaleEncoder.encode().blake2b32() + let data = scaleEncoder.encode() var container = encoder.singleValueContainer() try container.encode(BytesCodable(wrappedValue: data)) From 251f18a4ce0ac29a3db5f82463e71feb00b4360e Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 7 Oct 2022 15:33:26 +0500 Subject: [PATCH 018/229] add referendums retrieval --- novawallet.xcodeproj/project.pbxproj | 4 + .../Model/ReferendumMetadataLocal.swift | 6 + .../Model/ReferendumsInteractorError.swift | 2 + .../Referendums/ReferendumsInteractor.swift | 127 +++++++++++++++++- .../Referendums/ReferendumsPresenter.swift | 19 ++- .../Referendums/ReferendumsProtocols.swift | 5 + .../Parent/VoteChildPresenterFactory.swift | 11 +- 7 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index f9a6a9c30d..05e5f4228b 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1946,6 +1946,7 @@ 84E8AC7527BB975700402635 /* RMRKV1OperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8AC7427BB975700402635 /* RMRKV1OperationFactory.swift */; }; 84E8AC7727BBC8E400402635 /* NFTIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8AC7627BBC8E400402635 /* NFTIntegrationTests.swift */; }; 84E90BA128D0B51000529633 /* CheckboxControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E90BA028D0B51000529633 /* CheckboxControlView.swift */; }; + 84E9A05028F000AB00551DC4 /* ReferendumMetadataLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E9A04F28F000AB00551DC4 /* ReferendumMetadataLocal.swift */; }; 84EA0B2A25E579DF00AFB0DC /* AssetBalanceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EA0B2925E579DF00AFB0DC /* AssetBalanceViewModel.swift */; }; 84EB6C4E281999E100CFD8B2 /* PayoutTimeViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EB6C4D281999E100CFD8B2 /* PayoutTimeViewModelFactory.swift */; }; 84EBA4F027AD26A5000AEEAD /* AssetBalanceId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EBA4EF27AD26A5000AEEAD /* AssetBalanceId.swift */; }; @@ -4747,6 +4748,7 @@ 84E8AC7427BB975700402635 /* RMRKV1OperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RMRKV1OperationFactory.swift; sourceTree = ""; }; 84E8AC7627BBC8E400402635 /* NFTIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NFTIntegrationTests.swift; sourceTree = ""; }; 84E90BA028D0B51000529633 /* CheckboxControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxControlView.swift; sourceTree = ""; }; + 84E9A04F28F000AB00551DC4 /* ReferendumMetadataLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumMetadataLocal.swift; sourceTree = ""; }; 84EA0B2925E579DF00AFB0DC /* AssetBalanceViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetBalanceViewModel.swift; sourceTree = ""; }; 84EB6C4D281999E100CFD8B2 /* PayoutTimeViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayoutTimeViewModelFactory.swift; sourceTree = ""; }; 84EBA4EF27AD26A5000AEEAD /* AssetBalanceId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetBalanceId.swift; sourceTree = ""; }; @@ -10994,6 +10996,7 @@ 84D8753C28EB17B2004065BD /* GovernanceSharedState.swift */, 84A1742328ED3CF70096F943 /* ReferendumLocal.swift */, 84DD49F528EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift */, + 84E9A04F28F000AB00551DC4 /* ReferendumMetadataLocal.swift */, ); path = Model; sourceTree = ""; @@ -13975,6 +13978,7 @@ 8456C08227CF9DC9001282DE /* RemoteNftModel.swift in Sources */, 8401AEC42642A71D000B03E3 /* StakingRebondConfirmationWireframe.swift in Sources */, F4F3C3CB265BB12200C58400 /* CustomValidatorListViewModelFactory.swift in Sources */, + 84E9A05028F000AB00551DC4 /* ReferendumMetadataLocal.swift in Sources */, 84821E84275F93C700ADC8D2 /* TitleMultiValueView+Style.swift in Sources */, 84DA03D12758AA6800E8B326 /* BaseAccountImportWireframe.swift in Sources */, F4C201822728678400B0F3D0 /* ExtrinsicStatus.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift new file mode 100644 index 0000000000..708d7d8749 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift @@ -0,0 +1,6 @@ +import Foundation + +struct ReferendumMetadataLocal { + let name: String + let details: String +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift index 7ad37f990e..4e5f6ee5d0 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift @@ -5,4 +5,6 @@ enum ReferendumsInteractorError: Error { case priceSubscriptionFailed(_ internalError: Error) case balanceSubscriptionFailed(_ internalError: Error) case chainSaveFailed(_ internalError: Error) + case referendumsFetchFailed(_ internalError: Error) + case blockNumberSubscriptionFailed(_ internalError: Error) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 748a35689e..62ff85df19 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -1,7 +1,8 @@ import Foundation import RobinHood +import SubstrateSdk -final class ReferendumsInteractor: AnyProviderAutoCleaning { +final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleaning { weak var presenter: ReferendumsInteractorOutputProtocol? let selectedMetaAccount: MetaAccountModel @@ -9,10 +10,17 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning { let chainRegistry: ChainRegistryProtocol let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol + let referendumsOperationFactory: ReferendumsOperationFactoryProtocol let currencyManager: CurrencyManagerProtocol + let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? private var assetBalanceProvider: StreamableProvider? + private var blockNumberSubscription: CallbackStorageSubscription>? + + private lazy var localKeyFactory = LocalStorageKeyFactory() + + private var referendumsCancellable: CancellableCall? init( selectedMetaAccount: MetaAccountModel, @@ -20,6 +28,8 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning { chainRegistry: ChainRegistryProtocol, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + referendumsOperationFactory: ReferendumsOperationFactoryProtocol, + operationQueue: OperationQueue, currencyManager: CurrencyManagerProtocol ) { self.selectedMetaAccount = selectedMetaAccount @@ -27,12 +37,22 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning { self.chainRegistry = chainRegistry self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory + self.referendumsOperationFactory = referendumsOperationFactory + self.operationQueue = operationQueue self.currencyManager = currencyManager } private func clear() { clear(streamableProvider: &assetBalanceProvider) clear(singleValueProvider: &priceProvider) + + blockNumberSubscription = nil + + clearCancellable() + } + + private func clearCancellable() { + clear(cancellable: &referendumsCancellable) } private func continueSetup() { @@ -56,6 +76,46 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning { } subscribeToAssetPrice(for: chain) + + subscribeToBlockNumber(for: chain) + } + + private func subscribeToBlockNumber(for chain: ChainModel) { + guard let connection = chainRegistry.getConnection(for: chain.chainId) else { + presenter?.didReceiveError(.blockNumberSubscriptionFailed(ChainRegistryError.connectionUnavailable)) + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + presenter?.didReceiveError(.blockNumberSubscriptionFailed(ChainRegistryError.runtimeMetadaUnavailable)) + return + } + + do { + let localKey = try localKeyFactory.createFromStoragePath(.blockNumber, chainId: chain.chainId) + let request = UnkeyedSubscriptionRequest(storagePath: .blockNumber, localKey: localKey) + blockNumberSubscription = CallbackStorageSubscription( + request: request, + connection: connection, + runtimeService: runtimeProvider, + repository: nil, + operationQueue: operationQueue, + callbackQueue: .main + ) { [weak self] result in + switch result { + case let .success(resultData): + if let blockNumber = resultData?.value { + self?.presenter?.didReceiveBlockNumber(blockNumber) + + self?.provideReferendumsIfNeeded() + } + case let .failure(error): + self?.presenter?.didReceiveError(.blockNumberSubscriptionFailed(error)) + } + } + } catch { + presenter?.didReceiveError(.blockNumberSubscriptionFailed(error)) + } } private func subscribeToAssetBalance(for accountId: AccountId, chain: ChainModel) { @@ -79,10 +139,59 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning { } private func handleChainChange(for newChain: ChainModel) { + clear() + let accountResponse = selectedMetaAccount.fetch(for: newChain.accountRequest()) setup(with: accountResponse?.accountId, chain: newChain) } + + private func provideReferendumsIfNeeded() { + guard referendumsCancellable == nil else { + return + } + + guard let chain = governanceState.settings.value else { + presenter?.didReceiveError(.referendumsFetchFailed(PersistentValueSettingsError.missingValue)) + return + } + + guard let connection = chainRegistry.getConnection(for: chain.chainId) else { + presenter?.didReceiveError(.referendumsFetchFailed(ChainRegistryError.connectionUnavailable)) + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + presenter?.didReceiveError(.referendumsFetchFailed(ChainRegistryError.runtimeMetadaUnavailable)) + return + } + + let wrapper = referendumsOperationFactory.fetchAllReferendumsWrapper( + from: connection, + runtimeProvider: runtimeProvider + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.referendumsCancellable else { + return + } + + self?.referendumsCancellable = nil + + do { + let referendums = try wrapper.targetOperation.extractNoCancellableResultData() + self?.presenter?.didReceiveReferendums(referendums) + } catch { + self?.presenter?.didReceiveError(.referendumsFetchFailed(error)) + } + } + } + + referendumsCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } } extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { @@ -113,6 +222,22 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { } } } + + func becomeOnline() { + if let chain = governanceState.settings.value { + subscribeToBlockNumber(for: chain) + } + } + + func putOffline() { + blockNumberSubscription = nil + } + + func refresh() { + if governanceState.settings.value != nil { + provideReferendumsIfNeeded() + } + } } extension ReferendumsInteractor: WalletLocalSubscriptionHandler, WalletLocalStorageSubscriber { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 0424a37af2..cc031cdb7d 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -11,6 +11,9 @@ final class ReferendumsPresenter { private var freeBalance: BigUInt? private var chain: ChainModel? private var price: PriceData? + private var referendums: [ReferendumLocal]? + private var referendumsMetadata: [Referenda.ReferendumIndex: ReferendumMetadataLocal]? + private var blockNumber: BlockNumber? private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() @@ -46,9 +49,13 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { interactor.setup() } - func becomeOnline() {} + func becomeOnline() { + interactor.becomeOnline() + } - func putOffline() {} + func putOffline() { + interactor.putOffline() + } func selectChain() { guard let chain = chain, let asset = chain.utilityAsset() else { @@ -66,6 +73,14 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { } extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { + func didReceiveBlockNumber(_ blockNumber: BlockNumber) { + self.blockNumber = blockNumber + } + + func didReceiveReferendums(_ referendums: [ReferendumLocal]) { + self.referendums = referendums + } + func didReceiveSelectedChain(_ chain: ChainModel) { self.chain = chain diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 0d415b1f17..d2653a811d 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -11,12 +11,17 @@ protocol ReferendumsPresenterProtocol: AnyObject {} protocol ReferendumsInteractorInputProtocol: AnyObject { func setup() func saveSelected(chainModel: ChainModel) + func becomeOnline() + func putOffline() + func refresh() } protocol ReferendumsInteractorOutputProtocol: AnyObject { + func didReceiveReferendums(_ referendums: [ReferendumLocal]) func didReceiveSelectedChain(_ chain: ChainModel) func didReceiveAssetBalance(_ balance: AssetBalance?) func didReceivePrice(_ price: PriceData?) + func didReceiveBlockNumber(_ blockNumber: BlockNumber) func didReceiveError(_ error: ReferendumsInteractorError) } diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index c6e02436ea..c6a24339fc 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -96,12 +96,21 @@ final class VoteChildPresenterFactory { for state: GovernanceSharedState, wallet: MetaAccountModel ) -> ReferendumsInteractor { - ReferendumsInteractor( + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + let referendumOperationFactory = Gov2OperationFactory(requestFactory: requestFactory) + + return ReferendumsInteractor( selectedMetaAccount: wallet, governanceState: state, chainRegistry: chainRegistry, walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, priceLocalSubscriptionFactory: priceProviderFactory, + referendumsOperationFactory: referendumOperationFactory, + operationQueue: operationQueue, currencyManager: currencyManager ) } From 4eaf148c06dc42188f48b00329deb4ee5a82fd81 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 7 Oct 2022 18:18:54 +0500 Subject: [PATCH 019/229] add interactor implementation --- novawallet.xcodeproj/project.pbxproj | 24 +++++++++ .../GovMetadataLocalSubscriptionFactory.swift | 49 +++++++++++++++++++ .../Gov2MetadataProviderSource.swift | 10 ++++ .../GovMetadataLocalStorageHandler.swift | 15 ++++++ .../GovMetadataLocalStorageSubscriber.swift | 49 +++++++++++++++++++ .../Model/GovernanceSharedState.swift | 3 ++ .../Model/ReferendumMetadataLocal.swift | 2 +- .../Model/ReferendumsInteractorError.swift | 1 + .../Referendums/ReferendumsInteractor.swift | 44 ++++++++++++++++- .../Referendums/ReferendumsPresenter.swift | 39 +++++++++++++-- .../Referendums/ReferendumsProtocols.swift | 4 +- .../Parent/VoteChildPresenterFactory.swift | 3 +- 12 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift create mode 100644 novawallet/Common/DataProvider/Sources/Governance/Gov2MetadataProviderSource.swift create mode 100644 novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift create mode 100644 novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 05e5f4228b..c953faa991 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -395,6 +395,10 @@ 8411707A285B10F5006F4DFB /* XcmAssetTransferFee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84117079285B10F5006F4DFB /* XcmAssetTransferFee.swift */; }; 8411707C285B1214006F4DFB /* XcmTransfers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411707B285B1214006F4DFB /* XcmTransfers.swift */; }; 8411707F285B15E0006F4DFB /* XcmTransfersSyncService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411707E285B15E0006F4DFB /* XcmTransfersSyncService.swift */; }; + 8412219B28F04EA600715C82 /* GovMetadataLocalSubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219A28F04EA600715C82 /* GovMetadataLocalSubscriptionFactory.swift */; }; + 8412219E28F0514400715C82 /* Gov2MetadataProviderSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219D28F0514400715C82 /* Gov2MetadataProviderSource.swift */; }; + 841221A028F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219F28F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift */; }; + 841221A228F0520300715C82 /* GovMetadataLocalStorageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841221A128F0520300715C82 /* GovMetadataLocalStorageHandler.swift */; }; 8412AF992789AB76008A6C22 /* PolkadotExtensionMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412AF982789AB76008A6C22 /* PolkadotExtensionMetadata.swift */; }; 8412AF9B2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412AF9A2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift */; }; 841493DC2604C144000D8D1A /* SubscanRewardData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841493DB2604C144000D8D1A /* SubscanRewardData.swift */; }; @@ -3179,6 +3183,10 @@ 84117079285B10F5006F4DFB /* XcmAssetTransferFee.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcmAssetTransferFee.swift; sourceTree = ""; }; 8411707B285B1214006F4DFB /* XcmTransfers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcmTransfers.swift; sourceTree = ""; }; 8411707E285B15E0006F4DFB /* XcmTransfersSyncService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcmTransfersSyncService.swift; sourceTree = ""; }; + 8412219A28F04EA600715C82 /* GovMetadataLocalSubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalSubscriptionFactory.swift; sourceTree = ""; }; + 8412219D28F0514400715C82 /* Gov2MetadataProviderSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2MetadataProviderSource.swift; sourceTree = ""; }; + 8412219F28F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalStorageSubscriber.swift; sourceTree = ""; }; + 841221A128F0520300715C82 /* GovMetadataLocalStorageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalStorageHandler.swift; sourceTree = ""; }; 8412AF982789AB76008A6C22 /* PolkadotExtensionMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotExtensionMetadata.swift; sourceTree = ""; }; 8412AF9A2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotExtensionMetadataResponse.swift; sourceTree = ""; }; 841493DB2604C144000D8D1A /* SubscanRewardData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscanRewardData.swift; sourceTree = ""; }; @@ -6489,6 +6497,14 @@ path = XcmService; sourceTree = ""; }; + 8412219C28F0512B00715C82 /* Governance */ = { + isa = PBXGroup; + children = ( + 8412219D28F0514400715C82 /* Gov2MetadataProviderSource.swift */, + ); + path = Governance; + sourceTree = ""; + }; 84155DE8253980D700A27058 /* Services */ = { isa = PBXGroup; children = ( @@ -7749,6 +7765,7 @@ 842643BC28785A940031B5B5 /* TuringStakingLocalSubscriptionFactory.swift */, 84EF8D38288FCE8100265346 /* WalletListLocalSubscriptionFactory.swift */, 880855F928D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift */, + 8412219A28F04EA600715C82 /* GovMetadataLocalSubscriptionFactory.swift */, ); path = DataProvider; sourceTree = ""; @@ -7756,6 +7773,7 @@ 8463A70825E30000003B8160 /* Sources */ = { isa = PBXGroup; children = ( + 8412219C28F0512B00715C82 /* Governance */, 846A682A274693D400D1A47A /* Crowdloan */, 84EE6826264AD37B0026E6D3 /* Rewards */, 8463A71E25E39E07003B8160 /* StorageProviderSource.swift */, @@ -10816,6 +10834,8 @@ 84EF8D3D288FDA2100265346 /* WalletListLocalStorageSubscriber.swift */, 84EF8D3F288FDA7700265346 /* WalletListLocalStorageSubscriptionHandler.swift */, 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */, + 8412219F28F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift */, + 841221A128F0520300715C82 /* GovMetadataLocalStorageHandler.swift */, ); path = Subscription; sourceTree = ""; @@ -14232,6 +14252,7 @@ 8446F5F6281916D300B7A86C /* StakingRewardsHeaderCell.swift in Sources */, 84CA68D126BE99ED003B9453 /* RuntimeProviderFactory.swift in Sources */, 848F8B1928635A5600204BC4 /* TransferSetupPresenter.swift in Sources */, + 841221A028F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift in Sources */, 84100F3626A6069200A5054E /* IconTitleValueView.swift in Sources */, 842876AB24AE049B00D91AD8 /* SelectionItemViewProtocol.swift in Sources */, 8472C5AF265CF9C500E2481B /* StakingRewardDestConfirmViewLayout.swift in Sources */, @@ -14930,6 +14951,7 @@ 84EC2D18276B9DBC009B0BE1 /* PolkadotExtensionAccount.swift in Sources */, 8494D8552524633300614D8F /* WalletTransferTokenView.swift in Sources */, F4E17FCF272182E800FE36D3 /* MoonbeamAgreeRemarkRequest.swift in Sources */, + 841221A228F0520300715C82 /* GovMetadataLocalStorageHandler.swift in Sources */, 84720730277C335000F593DD /* DAppListFlowLayout.swift in Sources */, AE2C84DF25EF98BA00986716 /* AnyValidatorInfoInteractor.swift in Sources */, 8490142E24A935FE008F705E /* LoadableViewProtocol.swift in Sources */, @@ -14970,6 +14992,7 @@ 84C5ADE628141D21006D7388 /* LinkView.swift in Sources */, 84C2064028D1EAD2006D0D52 /* AccountAssetBalanceTrigger.swift in Sources */, 848FFE8325E686C200652AA5 /* StorageDecodingOperation.swift in Sources */, + 8412219E28F0514400715C82 /* Gov2MetadataProviderSource.swift in Sources */, 8488ECDF258CE118004591CC /* PurchaseCompleted.swift in Sources */, 84AE7AA727D36E4D00495267 /* IconDetailsGenericView.swift in Sources */, 840BF22726C2C8A600E3A955 /* ChainSyncEvents.swift in Sources */, @@ -15462,6 +15485,7 @@ 9A6A55297F41DAE45071BF57 /* ExportSeedInteractor.swift in Sources */, 886E8CF81EF2566D98D9693E /* ExportSeedViewFactory.swift in Sources */, C20ED4531583D0C8E38715E0 /* PurchaseProtocols.swift in Sources */, + 8412219B28F04EA600715C82 /* GovMetadataLocalSubscriptionFactory.swift in Sources */, 848F8B1F2863BB4000204BC4 /* TransferSetupPresenterFactory.swift in Sources */, 3CA86739CB09801714B194BD /* PurchaseWireframe.swift in Sources */, 84FB298C2639ABA500BE0FCD /* YourValidatorList.swift in Sources */, diff --git a/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift new file mode 100644 index 0000000000..081e34fdad --- /dev/null +++ b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift @@ -0,0 +1,49 @@ +import Foundation +import RobinHood + +typealias ReferendumMetadataMapping = [Referenda.ReferendumIndex: ReferendumMetadataLocal] + +protocol GovMetadataLocalSubscriptionFactoryProtocol: AnyObject { + func getMetadataProvider( + for chain: ChainModel + ) -> AnySingleValueProvider +} + +final class GovMetadataLocalSubscriptionFactory { + private var providers: [String: WeakWrapper] = [:] + + let storageFacade: StorageFacadeProtocol + + init(storageFacade: StorageFacadeProtocol) { + self.storageFacade = storageFacade + } +} + +extension GovMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { + func getMetadataProvider( + for chain: ChainModel + ) -> AnySingleValueProvider { + let identifier = "gov-metadata" + chain.chainId + + if let provider = providers[identifier]?.target as? SingleValueProvider { + return AnySingleValueProvider(provider) + } + + let repository: CoreDataRepository = + storageFacade.createRepository() + + let source = Gov2MetadataProviderSource() + + let trigger: DataProviderEventTrigger = [.onAddObserver, .onInitialization] + let provider = SingleValueProvider( + targetIdentifier: identifier, + source: AnySingleValueProviderSource(source), + repository: AnyDataProviderRepository(repository), + updateTrigger: trigger + ) + + providers[identifier] = WeakWrapper(target: provider) + + return AnySingleValueProvider(provider) + } +} diff --git a/novawallet/Common/DataProvider/Sources/Governance/Gov2MetadataProviderSource.swift b/novawallet/Common/DataProvider/Sources/Governance/Gov2MetadataProviderSource.swift new file mode 100644 index 0000000000..aa48bdc314 --- /dev/null +++ b/novawallet/Common/DataProvider/Sources/Governance/Gov2MetadataProviderSource.swift @@ -0,0 +1,10 @@ +import Foundation +import RobinHood + +final class Gov2MetadataProviderSource: SingleValueProviderSourceProtocol { + typealias Model = ReferendumMetadataMapping + + func fetchOperation() -> CompoundOperationWrapper { + CompoundOperationWrapper.createWithResult([:]) + } +} diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift new file mode 100644 index 0000000000..544fe6042c --- /dev/null +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift @@ -0,0 +1,15 @@ +import Foundation + +protocol GovMetadataLocalStorageHandler: AnyObject { + func handleGovMetadata( + result: Result, + chain: ChainModel + ) +} + +extension GovMetadataLocalStorageHandler { + func handleGovMetadata( + result _: Result, + chain _: ChainModel + ) {} +} diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift new file mode 100644 index 0000000000..c43649d04a --- /dev/null +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift @@ -0,0 +1,49 @@ +import Foundation +import RobinHood + +protocol GovMetadataLocalStorageSubscriber: AnyObject { + var govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { get } + + var govMetadataLocalSubscriptionHandler: GovMetadataLocalStorageHandler { get } + + func subscribeGovMetadata(for chain: ChainModel) -> AnySingleValueProvider +} + +extension GovMetadataLocalStorageSubscriber { + func subscribeGovMetadata(for chain: ChainModel) -> AnySingleValueProvider { + let provider = govMetadataLocalSubscriptionFactory.getMetadataProvider(for: chain) + + let updateClosure: ([DataProviderChange]) -> Void = { [weak self] changes in + let result = changes.reduceToLastChange() + self?.govMetadataLocalSubscriptionHandler.handleGovMetadata( + result: .success(result), + chain: chain + ) + return + } + + let failureClosure: (Error) -> Void = { [weak self] error in + self?.govMetadataLocalSubscriptionHandler.handleGovMetadata(result: .failure(error), chain: chain) + return + } + + let options = DataProviderObserverOptions( + alwaysNotifyOnRefresh: false, + waitsInProgressSyncOnAdd: false + ) + + provider.addObserver( + self, + deliverOn: .main, + executing: updateClosure, + failing: failureClosure, + options: options + ) + + return provider + } +} + +extension GovMetadataLocalStorageSubscriber where Self: GovMetadataLocalStorageHandler { + var govMetadataLocalSubscriptionHandler: GovMetadataLocalStorageHandler { self } +} diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index 0efc994ead..bf31aac019 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -3,11 +3,14 @@ import SoraKeystore final class GovernanceSharedState { let settings: GovernanceChainSettings + let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol init( chainRegistry: ChainRegistryProtocol = ChainRegistryFacade.sharedRegistry, + substrateStorageFacade: StorageFacadeProtocol = SubstrateDataStorageFacade.shared, internalSettings: SettingsManagerProtocol = SettingsManager.shared ) { settings = GovernanceChainSettings(chainRegistry: chainRegistry, settings: internalSettings) + govMetadataLocalSubscriptionFactory = GovMetadataLocalSubscriptionFactory(storageFacade: substrateStorageFacade) } } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift index 708d7d8749..94109caf2c 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift @@ -1,6 +1,6 @@ import Foundation -struct ReferendumMetadataLocal { +struct ReferendumMetadataLocal: Equatable, Codable { let name: String let details: String } diff --git a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift index 4e5f6ee5d0..bee06c193c 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift @@ -7,4 +7,5 @@ enum ReferendumsInteractorError: Error { case chainSaveFailed(_ internalError: Error) case referendumsFetchFailed(_ internalError: Error) case blockNumberSubscriptionFailed(_ internalError: Error) + case metadataSubscriptionFailed(_ internalError: Error) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 62ff85df19..0ccbed4933 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -14,9 +14,14 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani let currencyManager: CurrencyManagerProtocol let operationQueue: OperationQueue + var govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { + governanceState.govMetadataLocalSubscriptionFactory + } + private var priceProvider: AnySingleValueProvider? private var assetBalanceProvider: StreamableProvider? private var blockNumberSubscription: CallbackStorageSubscription>? + private var metadataProvider: AnySingleValueProvider? private lazy var localKeyFactory = LocalStorageKeyFactory() @@ -45,6 +50,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani private func clear() { clear(streamableProvider: &assetBalanceProvider) clear(singleValueProvider: &priceProvider) + clear(singleValueProvider: &metadataProvider) blockNumberSubscription = nil @@ -78,9 +84,14 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani subscribeToAssetPrice(for: chain) subscribeToBlockNumber(for: chain) + subscribeToMetadata(for: chain) } private func subscribeToBlockNumber(for chain: ChainModel) { + guard blockNumberSubscription == nil else { + return + } + guard let connection = chainRegistry.getConnection(for: chain.chainId) else { presenter?.didReceiveError(.blockNumberSubscriptionFailed(ChainRegistryError.connectionUnavailable)) return @@ -106,8 +117,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani case let .success(resultData): if let blockNumber = resultData?.value { self?.presenter?.didReceiveBlockNumber(blockNumber) - - self?.provideReferendumsIfNeeded() } case let .failure(error): self?.presenter?.didReceiveError(.blockNumberSubscriptionFailed(error)) @@ -138,6 +147,10 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) } + private func subscribeToMetadata(for chain: ChainModel) { + metadataProvider = subscribeGovMetadata(for: chain) + } + private func handleChainChange(for newChain: ChainModel) { clear() @@ -208,6 +221,16 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { } } + func remakeSubscriptions() { + clear() + + if let chain = governanceState.settings.value { + let accountResponse = selectedMetaAccount.fetch(for: chain.accountRequest()) + + setup(with: accountResponse?.accountId, chain: chain) + } + } + func saveSelected(chainModel: ChainModel) { if chainModel.chainId != governanceState.settings.value?.chainId { clear() @@ -236,6 +259,23 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { func refresh() { if governanceState.settings.value != nil { provideReferendumsIfNeeded() + + metadataProvider?.refresh() + } + } +} + +extension ReferendumsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataLocalStorageHandler { + func handleGovMetadata(result: Result, chain: ChainModel) { + guard let currentChain = governanceState.settings.value, currentChain.chainId == chain.chainId else { + return + } + + switch result { + case let .success(mapping): + presenter?.didReceiveReferendumsMetadata(mapping) + case let .failure(error): + presenter?.didReceiveError(.metadataSubscriptionFailed(error)) } } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index cc031cdb7d..9052fe1749 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -7,12 +7,13 @@ final class ReferendumsPresenter { let interactor: ReferendumsInteractorInputProtocol let wireframe: ReferendumsWireframeProtocol + let logger: LoggerProtocol private var freeBalance: BigUInt? private var chain: ChainModel? private var price: PriceData? private var referendums: [ReferendumLocal]? - private var referendumsMetadata: [Referenda.ReferendumIndex: ReferendumMetadataLocal]? + private var referendumsMetadata: ReferendumMetadataMapping? private var blockNumber: BlockNumber? private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() @@ -20,10 +21,12 @@ final class ReferendumsPresenter { init( interactor: ReferendumsInteractorInputProtocol, wireframe: ReferendumsWireframeProtocol, - localizationManager: LocalizationManagerProtocol + localizationManager: LocalizationManagerProtocol, + logger: LoggerProtocol ) { self.interactor = interactor self.wireframe = wireframe + self.logger = logger self.localizationManager = localizationManager } @@ -73,8 +76,14 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { } extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { + func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) { + referendumsMetadata = metadata + } + func didReceiveBlockNumber(_ blockNumber: BlockNumber) { self.blockNumber = blockNumber + + interactor.refresh() } func didReceiveReferendums(_ referendums: [ReferendumLocal]) { @@ -97,7 +106,31 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { self.price = price } - func didReceiveError(_: ReferendumsInteractorError) {} + func didReceiveError(_ error: ReferendumsInteractorError) { + logger.error("Did receive error: \(error)") + + switch error { + case .settingsLoadFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.setup() + } + case .chainSaveFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + if let chain = self?.chain { + self?.interactor.saveSelected(chainModel: chain) + } + } + case .referendumsFetchFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refresh() + } + case .blockNumberSubscriptionFailed, .priceSubscriptionFailed, .balanceSubscriptionFailed, + .metadataSubscriptionFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + } + } } extension ReferendumsPresenter: AssetSelectionDelegate { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index d2653a811d..e721dbfef1 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -14,10 +14,12 @@ protocol ReferendumsInteractorInputProtocol: AnyObject { func becomeOnline() func putOffline() func refresh() + func remakeSubscriptions() } protocol ReferendumsInteractorOutputProtocol: AnyObject { func didReceiveReferendums(_ referendums: [ReferendumLocal]) + func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) func didReceiveSelectedChain(_ chain: ChainModel) func didReceiveAssetBalance(_ balance: AssetBalance?) func didReceivePrice(_ price: PriceData?) @@ -25,7 +27,7 @@ protocol ReferendumsInteractorOutputProtocol: AnyObject { func didReceiveError(_ error: ReferendumsInteractorError) } -protocol ReferendumsWireframeProtocol: AnyObject { +protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable { func selectChain( from view: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index c6a24339fc..52ea3a242d 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -162,7 +162,8 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { let presenter = ReferendumsPresenter( interactor: interactor, wireframe: wireframe, - localizationManager: localizationManager + localizationManager: localizationManager, + logger: logger ) presenter.view = view From ba57df1959e151fccbf7e3786a88b142e0b37e3b Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 7 Oct 2022 20:22:02 +0500 Subject: [PATCH 020/229] fix review --- novawallet.xcodeproj/project.pbxproj | 8 ++++---- .../Substrate/Types/Referenda/ReferendumInfo.swift | 14 +++++++------- ...ft => ReferendumDecidingFunctionProtocol.swift} | 4 ++-- .../Vote/Governance/Model/ReferendumLocal.swift | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) rename novawallet/Modules/Vote/Governance/Model/{ReferendumLocalDecidingFunction.swift => ReferendumDecidingFunctionProtocol.swift} (95%) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index c953faa991..63bb94ec4b 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1886,7 +1886,7 @@ 84DC3CE7279679230038E2ED /* SubqueryHistory+Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DC3CE6279679230038E2ED /* SubqueryHistory+Wallet.swift */; }; 84DC5A1328BAA8020014E081 /* LedgerInvaliDataPolkadotReason.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DC5A1228BAA8020014E081 /* LedgerInvaliDataPolkadotReason.swift */; }; 84DD49F428EE91ED00B804F3 /* Gov2LocalMappingFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */; }; - 84DD49F628EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD49F528EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift */; }; + 84DD49F628EE974B00B804F3 /* ReferendumDecidingFunctionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD49F528EE974B00B804F3 /* ReferendumDecidingFunctionProtocol.swift */; }; 84DD49F828EEAFFF00B804F3 /* DecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD49F728EEAFFF00B804F3 /* DecimalTests.swift */; }; 84DD5F21263CB6BE00425ACF /* UnbondCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD5F20263CB6BE00425ACF /* UnbondCall.swift */; }; 84DD5F26263D72C400425ACF /* ExtrinsicFeeProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DD5F25263D72C400425ACF /* ExtrinsicFeeProxy.swift */; }; @@ -4691,7 +4691,7 @@ 84DC3CE6279679230038E2ED /* SubqueryHistory+Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubqueryHistory+Wallet.swift"; sourceTree = ""; }; 84DC5A1228BAA8020014E081 /* LedgerInvaliDataPolkadotReason.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LedgerInvaliDataPolkadotReason.swift; sourceTree = ""; }; 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2LocalMappingFactory.swift; sourceTree = ""; }; - 84DD49F528EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLocalDecidingFunction.swift; sourceTree = ""; }; + 84DD49F528EE974B00B804F3 /* ReferendumDecidingFunctionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDecidingFunctionProtocol.swift; sourceTree = ""; }; 84DD49F728EEAFFF00B804F3 /* DecimalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecimalTests.swift; sourceTree = ""; }; 84DD5F20263CB6BE00425ACF /* UnbondCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnbondCall.swift; sourceTree = ""; }; 84DD5F25263D72C400425ACF /* ExtrinsicFeeProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicFeeProxy.swift; sourceTree = ""; }; @@ -11015,7 +11015,7 @@ children = ( 84D8753C28EB17B2004065BD /* GovernanceSharedState.swift */, 84A1742328ED3CF70096F943 /* ReferendumLocal.swift */, - 84DD49F528EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift */, + 84DD49F528EE974B00B804F3 /* ReferendumDecidingFunctionProtocol.swift */, 84E9A04F28F000AB00551DC4 /* ReferendumMetadataLocal.swift */, ); path = Model; @@ -16191,7 +16191,7 @@ 3AD7635AFA1F7E66A3C00F56 /* ParitySignerAddressesInteractor.swift in Sources */, 940DA38E4586A27D7F3E0C67 /* ParitySignerAddressesViewController.swift in Sources */, E8F04B9E557AD6BD0279EA6F /* ParitySignerAddressesViewLayout.swift in Sources */, - 84DD49F628EE974B00B804F3 /* ReferendumLocalDecidingFunction.swift in Sources */, + 84DD49F628EE974B00B804F3 /* ReferendumDecidingFunctionProtocol.swift in Sources */, 01F973625B78736D5EEA86F6 /* ParitySignerAddressesViewFactory.swift in Sources */, ECD4EB7314609007CE35461E /* ParitySignerAddConfirmProtocols.swift in Sources */, 6D622CD4A83EEC1F135B66A8 /* ParitySignerAddConfirmWireframe.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift index f1145b0251..28d52bb648 100644 --- a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift @@ -31,12 +31,12 @@ enum ReferendumInfo: Decodable { let decisionDeposit: Referenda.Deposit? } - case ongoing(_ status: OngoingStatus) - case approved(_ status: CompletedStatus) - case rejected(_ status: CompletedStatus) - case cancelled(_ status: CompletedStatus) - case timedOut(_ status: CompletedStatus) - case killed(_ atBlock: Moment) + case ongoing(OngoingStatus) + case approved(CompletedStatus) + case rejected(CompletedStatus) + case cancelled(CompletedStatus) + case timedOut(CompletedStatus) + case killed(atBlock: Moment) case unknown public init(from decoder: Decoder) throws { @@ -61,7 +61,7 @@ enum ReferendumInfo: Decodable { self = .timedOut(status) case "Killed": let since = try container.decode(StringScaleMapper.self).value - self = .killed(since) + self = .killed(atBlock: since) default: self = .unknown } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift similarity index 95% rename from novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift rename to novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift index dc1a6d4909..7f95fa9184 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocalDecidingFunction.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift @@ -1,10 +1,10 @@ import Foundation -protocol ReferendumLocalDecidingFunction { +protocol ReferendumDecidingFunctionProtocol { func calculateThreshold(for block: BlockNumber) -> Decimal? } -struct Gov2LocalDecidingFunction: ReferendumLocalDecidingFunction { +struct Gov2LocalDecidingFunction: ReferendumDecidingFunctionProtocol { let curve: Referenda.Curve let startBlock: BlockNumber let period: Moment diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 15eef74110..c4b68fed61 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -35,8 +35,8 @@ struct SupportAndVotesLocal { } /// nil if not deciding yet - let approvalFunction: ReferendumLocalDecidingFunction? - let supportFunction: ReferendumLocalDecidingFunction? + let approvalFunction: ReferendumDecidingFunctionProtocol? + let supportFunction: ReferendumDecidingFunctionProtocol? func isPassing(at block: BlockNumber) -> Bool { guard From 96706c7a3999a0e652b36844a81fa843f63a40dd Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 8 Oct 2022 00:31:00 +0500 Subject: [PATCH 021/229] add votes fetching --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../ConvictionVoting/ConvictionVoting.swift | 23 +++++++- .../Model/ReferendumAccountVoteLocal.swift | 38 +++++++++++++ .../Operation/Gov2OperationFactory.swift | 43 +++++++++++++++ .../GovernanceOperationProtocols.swift | 6 ++ .../Model/ReferendumsInteractorError.swift | 1 + .../Referendums/ReferendumsInteractor.swift | 55 +++++++++++++++++++ .../Referendums/ReferendumsPresenter.swift | 7 ++- .../Referendums/ReferendumsProtocols.swift | 1 + .../Gov2OperationFactoryTests.swift | 42 ++++++++++++++ 10 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 87d1e7435c..f7c8fd17f9 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -399,6 +399,7 @@ 8412219E28F0514400715C82 /* Gov2MetadataProviderSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219D28F0514400715C82 /* Gov2MetadataProviderSource.swift */; }; 841221A028F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219F28F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift */; }; 841221A228F0520300715C82 /* GovMetadataLocalStorageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841221A128F0520300715C82 /* GovMetadataLocalStorageHandler.swift */; }; + 841221A428F0A3F200715C82 /* ReferendumAccountVoteLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */; }; 8412AF992789AB76008A6C22 /* PolkadotExtensionMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412AF982789AB76008A6C22 /* PolkadotExtensionMetadata.swift */; }; 8412AF9B2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412AF9A2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift */; }; 841493DC2604C144000D8D1A /* SubscanRewardData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841493DB2604C144000D8D1A /* SubscanRewardData.swift */; }; @@ -3188,6 +3189,7 @@ 8412219D28F0514400715C82 /* Gov2MetadataProviderSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2MetadataProviderSource.swift; sourceTree = ""; }; 8412219F28F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalStorageSubscriber.swift; sourceTree = ""; }; 841221A128F0520300715C82 /* GovMetadataLocalStorageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalStorageHandler.swift; sourceTree = ""; }; + 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumAccountVoteLocal.swift; sourceTree = ""; }; 8412AF982789AB76008A6C22 /* PolkadotExtensionMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotExtensionMetadata.swift; sourceTree = ""; }; 8412AF9A2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotExtensionMetadataResponse.swift; sourceTree = ""; }; 841493DB2604C144000D8D1A /* SubscanRewardData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscanRewardData.swift; sourceTree = ""; }; @@ -11019,6 +11021,7 @@ 84A1742328ED3CF70096F943 /* ReferendumLocal.swift */, 84DD49F528EE974B00B804F3 /* ReferendumDecidingFunctionProtocol.swift */, 84E9A04F28F000AB00551DC4 /* ReferendumMetadataLocal.swift */, + 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */, ); path = Model; sourceTree = ""; @@ -14505,6 +14508,7 @@ 847297A2260B3146009B86D0 /* ChangeTargetsSelectValidatorsStartWireframe.swift in Sources */, 849D755B2756910A007726C3 /* RoundedView+Style.swift in Sources */, 84038FEC26FFBA4D00C73F3F /* PriceLocalStorageSubscriber.swift in Sources */, + 841221A428F0A3F200715C82 /* ReferendumAccountVoteLocal.swift in Sources */, 8473D4082657E9AD00B394B2 /* CrowdloanLastContribution.swift in Sources */, 841E5557282E531600C8438F /* ParaStkNetworkInfoOperationFactory.swift in Sources */, 84A2C90224E07E440020D3B7 /* CryptoType+Utils.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index e7293a9dfe..d50244ff8d 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -3,7 +3,7 @@ import SubstrateSdk import BigInt enum ConvictionVoting { - typealias PollIndex = UInt16 + typealias PollIndex = UInt32 enum Conviction: UInt8, Decodable { /// 0.1x votes, unlocked. @@ -22,6 +22,27 @@ enum ConvictionVoting { case locked6x case unknown + + func votes(for balance: BigUInt) -> BigUInt? { + switch self { + case .none: + return balance / 10 + case .locked1x: + return balance + case .locked2x: + return 2 * balance + case .locked3x: + return 4 * balance + case .locked4x: + return 8 * balance + case .locked5x: + return 16 * balance + case .locked6x: + return 32 * balance + case .unknown: + return nil + } + } } struct Vote: Decodable { diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift new file mode 100644 index 0000000000..2cb5ae846e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift @@ -0,0 +1,38 @@ +import Foundation +import BigInt + +struct ReferendumAccountVoteLocal { + /// post conviction votes for referendum + let ayes: BigUInt + let nays: BigUInt + + init?(accountVote: ConvictionVoting.AccountVote) { + switch accountVote { + case let .split(split): + self.init(accountVoteSplit: split) + case let .standard(standard): + self.init(accountVoteStandard: standard) + case .unknown: + return nil + } + } + + init(accountVoteSplit: ConvictionVoting.AccountVoteSplit) { + ayes = accountVoteSplit.aye + nays = accountVoteSplit.nay + } + + init?(accountVoteStandard: ConvictionVoting.AccountVoteStandard) { + guard let votes = accountVoteStandard.vote.conviction.votes(for: accountVoteStandard.balance) else { + return nil + } + + if accountVoteStandard.vote.aye { + ayes = votes + nays = 0 + } else { + ayes = 0 + nays = votes + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index af0f181613..ab6851ae71 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -212,4 +212,47 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } + + func fetchAccountVotes( + for accountId: AccountId, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[Referenda.ReferendumIndex: ReferendumAccountVoteLocal]> { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let request = MapRemoteStorageRequest(storagePath: ConvictionVoting.votingFor) { + BytesCodable(wrappedValue: accountId) + } + + let votesWrapper: CompoundOperationWrapper<[ConvictionVoting.VotingForKey: ConvictionVoting.Voting]> = + requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: ConvictionVoting.votingFor, + factory: { try codingFactoryOperation.extractNoCancellableResultData() } + ) + + votesWrapper.addDependency(operations: [codingFactoryOperation]) + + let mappingOperation = ClosureOperation<[Referenda.ReferendumIndex: ReferendumAccountVoteLocal]> { + let votes = try votesWrapper.targetOperation.extractNoCancellableResultData().values + + return votes.reduce(into: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]()) { result, voting in + switch voting { + case let .casting(castingVoting): + castingVoting.votes.forEach { vote in + result[vote.pollIndex] = ReferendumAccountVoteLocal(accountVote: vote.accountVote) + } + case .delegating, .unknown: + break + } + } + } + + mappingOperation.addDependency(votesWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + votesWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } } diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift index 1e2e248f55..44a6caf88b 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -7,4 +7,10 @@ protocol ReferendumsOperationFactoryProtocol { from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol ) -> CompoundOperationWrapper<[ReferendumLocal]> + + func fetchAccountVotes( + for accountId: AccountId, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[Referenda.ReferendumIndex: ReferendumAccountVoteLocal]> } diff --git a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift index bee06c193c..f2d6b5ba71 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift @@ -8,4 +8,5 @@ enum ReferendumsInteractorError: Error { case referendumsFetchFailed(_ internalError: Error) case blockNumberSubscriptionFailed(_ internalError: Error) case metadataSubscriptionFailed(_ internalError: Error) + case votesFetchFailed(_ internalError: Error) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 0ccbed4933..3d3c883fef 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -26,6 +26,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani private lazy var localKeyFactory = LocalStorageKeyFactory() private var referendumsCancellable: CancellableCall? + private var votesCancellable: CancellableCall? init( selectedMetaAccount: MetaAccountModel, @@ -205,6 +206,59 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } + + private func provideVotesIfNeeded() { + guard votesCancellable == nil else { + return + } + + guard let chain = governanceState.settings.value else { + presenter?.didReceiveError(.votesFetchFailed(PersistentValueSettingsError.missingValue)) + return + } + + guard let connection = chainRegistry.getConnection(for: chain.chainId) else { + presenter?.didReceiveError(.votesFetchFailed(ChainRegistryError.connectionUnavailable)) + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + presenter?.didReceiveError(.votesFetchFailed(ChainRegistryError.runtimeMetadaUnavailable)) + return + } + + guard let accountId = selectedMetaAccount.fetch(for: chain.accountRequest())?.accountId else { + presenter?.didReceiveVotes([:]) + return + } + + let wrapper = referendumsOperationFactory.fetchAccountVotes( + for: accountId, + from: connection, + runtimeProvider: runtimeProvider + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.votesCancellable else { + return + } + + self?.votesCancellable = nil + + do { + let votes = try wrapper.targetOperation.extractNoCancellableResultData() + self?.presenter?.didReceiveVotes(votes) + } catch { + self?.presenter?.didReceiveError(.votesFetchFailed(error)) + } + } + } + + votesCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } } extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { @@ -259,6 +313,7 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { func refresh() { if governanceState.settings.value != nil { provideReferendumsIfNeeded() + provideVotesIfNeeded() metadataProvider?.refresh() } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 9052fe1749..8e0125fcd7 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -14,6 +14,7 @@ final class ReferendumsPresenter { private var price: PriceData? private var referendums: [ReferendumLocal]? private var referendumsMetadata: ReferendumMetadataMapping? + private var votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]? private var blockNumber: BlockNumber? private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() @@ -76,6 +77,10 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { } extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { + func didReceiveVotes(_ votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]) { + self.votes = votes + } + func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) { referendumsMetadata = metadata } @@ -120,7 +125,7 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { self?.interactor.saveSelected(chainModel: chain) } } - case .referendumsFetchFailed: + case .referendumsFetchFailed, .votesFetchFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in self?.interactor.refresh() } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index e721dbfef1..bcd128a2a2 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -20,6 +20,7 @@ protocol ReferendumsInteractorInputProtocol: AnyObject { protocol ReferendumsInteractorOutputProtocol: AnyObject { func didReceiveReferendums(_ referendums: [ReferendumLocal]) func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) + func didReceiveVotes(_ votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]) func didReceiveSelectedChain(_ chain: ChainModel) func didReceiveAssetBalance(_ balance: AssetBalance?) func didReceivePrice(_ price: PriceData?) diff --git a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift index 063b930180..6e8c880d93 100644 --- a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift +++ b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift @@ -47,4 +47,46 @@ class Gov2OperationFactoryTests: XCTestCase { XCTFail("Unexpected error: \(error)") } } + + func testFetchLocalVotes() throws { + // given + + let storageFacade = SubstrateStorageTestFacade() + let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) + let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" + let accountId = try "5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc".toAccountId() + let operationQueue = OperationQueue() + + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + guard let connection = chainRegistry.getConnection(for: chainId) else { + XCTFail("Can't get connection for chain id \(chainId)") + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + XCTFail("Can't get runtime provider for chain id \(chainId)") + return + } + + // when + + let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) + + let wrapper = operationFactory.fetchAccountVotes(for: accountId, from: connection, runtimeProvider: runtimeProvider) + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: true) + + // then + + do { + let votes = try wrapper.targetOperation.extractNoCancellableResultData() + Logger.shared.info("Votes: \(votes)") + } catch { + XCTFail("Unexpected error: \(error)") + } + } } From 8d764d93ed4ee38264fccc704b05b7494e179b2f Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 8 Oct 2022 10:49:46 +0500 Subject: [PATCH 022/229] integrate block estimation time --- novawallet.xcodeproj/project.pbxproj | 4 + .../Model/GovernanceServiceFactory.swift | 57 ++++++++ .../Model/GovernanceSharedState.swift | 7 + .../Model/ReferendumsInteractorError.swift | 2 + .../Referendums/ReferendumsInteractor.swift | 133 +++++++++++++----- .../Referendums/ReferendumsPresenter.swift | 11 +- .../Referendums/ReferendumsProtocols.swift | 2 + .../Parent/VoteChildPresenterFactory.swift | 24 ++++ 8 files changed, 206 insertions(+), 34 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Model/GovernanceServiceFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index f7c8fd17f9..03ce5018d9 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -400,6 +400,7 @@ 841221A028F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219F28F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift */; }; 841221A228F0520300715C82 /* GovMetadataLocalStorageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841221A128F0520300715C82 /* GovMetadataLocalStorageHandler.swift */; }; 841221A428F0A3F200715C82 /* ReferendumAccountVoteLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */; }; + 841221A628F13BA100715C82 /* GovernanceServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841221A528F13BA100715C82 /* GovernanceServiceFactory.swift */; }; 8412AF992789AB76008A6C22 /* PolkadotExtensionMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412AF982789AB76008A6C22 /* PolkadotExtensionMetadata.swift */; }; 8412AF9B2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412AF9A2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift */; }; 841493DC2604C144000D8D1A /* SubscanRewardData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841493DB2604C144000D8D1A /* SubscanRewardData.swift */; }; @@ -3190,6 +3191,7 @@ 8412219F28F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalStorageSubscriber.swift; sourceTree = ""; }; 841221A128F0520300715C82 /* GovMetadataLocalStorageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalStorageHandler.swift; sourceTree = ""; }; 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumAccountVoteLocal.swift; sourceTree = ""; }; + 841221A528F13BA100715C82 /* GovernanceServiceFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceServiceFactory.swift; sourceTree = ""; }; 8412AF982789AB76008A6C22 /* PolkadotExtensionMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotExtensionMetadata.swift; sourceTree = ""; }; 8412AF9A2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotExtensionMetadataResponse.swift; sourceTree = ""; }; 841493DB2604C144000D8D1A /* SubscanRewardData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscanRewardData.swift; sourceTree = ""; }; @@ -11022,6 +11024,7 @@ 84DD49F528EE974B00B804F3 /* ReferendumDecidingFunctionProtocol.swift */, 84E9A04F28F000AB00551DC4 /* ReferendumMetadataLocal.swift */, 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */, + 841221A528F13BA100715C82 /* GovernanceServiceFactory.swift */, ); path = Model; sourceTree = ""; @@ -14003,6 +14006,7 @@ 84D9C8F328ADA42F007FB23B /* Data+Chunk.swift in Sources */, 8456C08227CF9DC9001282DE /* RemoteNftModel.swift in Sources */, 8401AEC42642A71D000B03E3 /* StakingRebondConfirmationWireframe.swift in Sources */, + 841221A628F13BA100715C82 /* GovernanceServiceFactory.swift in Sources */, F4F3C3CB265BB12200C58400 /* CustomValidatorListViewModelFactory.swift in Sources */, 84E9A05028F000AB00551DC4 /* ReferendumMetadataLocal.swift in Sources */, 84821E84275F93C700ADC8D2 /* TitleMultiValueView+Style.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceServiceFactory.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceServiceFactory.swift new file mode 100644 index 0000000000..65651dc718 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceServiceFactory.swift @@ -0,0 +1,57 @@ +import Foundation +import RobinHood + +protocol GovernanceServiceFactoryProtocol { + func createBlockTimeService(for chainId: ChainModel.Id) throws -> BlockTimeEstimationServiceProtocol +} + +final class GovernanceServiceFactory: GovernanceServiceFactoryProtocol { + let chainRegisty: ChainRegistryProtocol + let storageFacade: StorageFacadeProtocol + let eventCenter: EventCenterProtocol + let operationQueue: OperationQueue + let logger: LoggerProtocol + + private lazy var substrateDataProviderFactory = SubstrateDataProviderFactory( + facade: storageFacade, + operationManager: OperationManager(operationQueue: operationQueue) + ) + + init( + chainRegisty: ChainRegistryProtocol, + storageFacade: StorageFacadeProtocol, + eventCenter: EventCenterProtocol, + operationQueue: OperationQueue, + logger: LoggerProtocol + ) { + self.chainRegisty = chainRegisty + self.storageFacade = storageFacade + self.eventCenter = eventCenter + self.operationQueue = operationQueue + self.logger = logger + } + + func createBlockTimeService(for chainId: ChainModel.Id) throws -> BlockTimeEstimationServiceProtocol { + guard let runtimeService = chainRegisty.getRuntimeProvider(for: chainId) else { + throw ChainRegistryError.runtimeMetadaUnavailable + } + + guard let connection = chainRegisty.getConnection(for: chainId) else { + throw ChainRegistryError.connectionUnavailable + } + + let repositoryFactory = SubstrateRepositoryFactory(storageFacade: storageFacade) + + let repository = repositoryFactory.createChainStorageItemRepository() + + return BlockTimeEstimationService( + chainId: chainId, + connection: connection, + runtimeService: runtimeService, + repository: repository, + eventCenter: eventCenter, + operationQueue: operationQueue, + logger: logger + ) + } +} diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index bf31aac019..614b7fe4e3 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -4,13 +4,20 @@ import SoraKeystore final class GovernanceSharedState { let settings: GovernanceChainSettings let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol + private(set) var blockTimeService: BlockTimeEstimationServiceProtocol? init( chainRegistry: ChainRegistryProtocol = ChainRegistryFacade.sharedRegistry, substrateStorageFacade: StorageFacadeProtocol = SubstrateDataStorageFacade.shared, + blockTimeService: BlockTimeEstimationServiceProtocol? = nil, internalSettings: SettingsManagerProtocol = SettingsManager.shared ) { settings = GovernanceChainSettings(chainRegistry: chainRegistry, settings: internalSettings) govMetadataLocalSubscriptionFactory = GovMetadataLocalSubscriptionFactory(storageFacade: substrateStorageFacade) + self.blockTimeService = blockTimeService + } + + func replaceBlockTimeService(_ newService: BlockTimeEstimationServiceProtocol?) { + blockTimeService = newService } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift index f2d6b5ba71..3f12c666a9 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift @@ -9,4 +9,6 @@ enum ReferendumsInteractorError: Error { case blockNumberSubscriptionFailed(_ internalError: Error) case metadataSubscriptionFailed(_ internalError: Error) case votesFetchFailed(_ internalError: Error) + case blockTimeFetchFailed(_ internalError: Error) + case blockTimeServiceFailed(_ internalError: Error) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 3d3c883fef..b98806cb51 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -1,6 +1,7 @@ import Foundation import RobinHood import SubstrateSdk +import SoraFoundation final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleaning { weak var presenter: ReferendumsInteractorOutputProtocol? @@ -11,7 +12,10 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let referendumsOperationFactory: ReferendumsOperationFactoryProtocol + let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol let currencyManager: CurrencyManagerProtocol + let applicationHandler: ApplicationHandlerProtocol + let serviceFactory: GovernanceServiceFactoryProtocol let operationQueue: OperationQueue var govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { @@ -20,13 +24,14 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani private var priceProvider: AnySingleValueProvider? private var assetBalanceProvider: StreamableProvider? - private var blockNumberSubscription: CallbackStorageSubscription>? + private var blockNumberSubscription: AnyDataProvider? private var metadataProvider: AnySingleValueProvider? private lazy var localKeyFactory = LocalStorageKeyFactory() private var referendumsCancellable: CancellableCall? private var votesCancellable: CancellableCall? + private var blockTimeCancellable: CancellableCall? init( selectedMetaAccount: MetaAccountModel, @@ -35,6 +40,9 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, referendumsOperationFactory: ReferendumsOperationFactoryProtocol, + generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, + serviceFactory: GovernanceServiceFactoryProtocol, + applicationHandler: ApplicationHandlerProtocol, operationQueue: OperationQueue, currencyManager: CurrencyManagerProtocol ) { @@ -44,15 +52,24 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory self.referendumsOperationFactory = referendumsOperationFactory + self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory + self.serviceFactory = serviceFactory self.operationQueue = operationQueue + self.applicationHandler = applicationHandler self.currencyManager = currencyManager } + deinit { + clear() + } + private func clear() { clear(streamableProvider: &assetBalanceProvider) clear(singleValueProvider: &priceProvider) clear(singleValueProvider: &metadataProvider) + clearBlockTimeService() + blockNumberSubscription = nil clearCancellable() @@ -60,9 +77,18 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani private func clearCancellable() { clear(cancellable: &referendumsCancellable) + clear(cancellable: &votesCancellable) + clear(cancellable: &blockTimeCancellable) + } + + private func clearBlockTimeService() { + governanceState.blockTimeService?.throttle() + governanceState.replaceBlockTimeService(nil) } private func continueSetup() { + applicationHandler.delegate = self + guard let chain = governanceState.settings.value else { presenter?.didReceiveError(.settingsLoadFailed) return @@ -84,48 +110,31 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani subscribeToAssetPrice(for: chain) + setupBlockTimeService(for: chain) + provideBlockTime() + subscribeToBlockNumber(for: chain) subscribeToMetadata(for: chain) } - private func subscribeToBlockNumber(for chain: ChainModel) { - guard blockNumberSubscription == nil else { - return - } + private func setupBlockTimeService(for chain: ChainModel) { + do { + let blockTimeService = try serviceFactory.createBlockTimeService(for: chain.chainId) - guard let connection = chainRegistry.getConnection(for: chain.chainId) else { - presenter?.didReceiveError(.blockNumberSubscriptionFailed(ChainRegistryError.connectionUnavailable)) - return + governanceState.replaceBlockTimeService(blockTimeService) + + blockTimeService.setup() + } catch { + presenter?.didReceiveError(.blockTimeServiceFailed(error)) } + } - guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { - presenter?.didReceiveError(.blockNumberSubscriptionFailed(ChainRegistryError.runtimeMetadaUnavailable)) + private func subscribeToBlockNumber(for chain: ChainModel) { + guard blockNumberSubscription == nil else { return } - do { - let localKey = try localKeyFactory.createFromStoragePath(.blockNumber, chainId: chain.chainId) - let request = UnkeyedSubscriptionRequest(storagePath: .blockNumber, localKey: localKey) - blockNumberSubscription = CallbackStorageSubscription( - request: request, - connection: connection, - runtimeService: runtimeProvider, - repository: nil, - operationQueue: operationQueue, - callbackQueue: .main - ) { [weak self] result in - switch result { - case let .success(resultData): - if let blockNumber = resultData?.value { - self?.presenter?.didReceiveBlockNumber(blockNumber) - } - case let .failure(error): - self?.presenter?.didReceiveError(.blockNumberSubscriptionFailed(error)) - } - } - } catch { - presenter?.didReceiveError(.blockNumberSubscriptionFailed(error)) - } + blockNumberSubscription = subscribeToBlockNumber(for: chain.chainId) } private func subscribeToAssetBalance(for accountId: AccountId, chain: ChainModel) { @@ -160,6 +169,36 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani setup(with: accountResponse?.accountId, chain: newChain) } + private func provideBlockTime() { + guard blockTimeCancellable == nil, let blockTimeService = governanceState.blockTimeService else { + return + } + + let blockTimeOperation = blockTimeService.createEstimatedBlockTimeOperation() + + blockTimeOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard self?.blockTimeCancellable === blockTimeOperation else { + return + } + + self?.blockTimeCancellable = nil + + do { + let blockTime = try blockTimeOperation.extractNoCancellableResultData().blockTime + + self?.presenter?.didReceiveBlockTime(blockTime) + } catch { + self?.presenter?.didReceiveError(.blockTimeFetchFailed(error)) + } + } + } + + blockTimeCancellable = blockTimeOperation + + operationQueue.addOperation(blockTimeOperation) + } + private func provideReferendumsIfNeeded() { guard referendumsCancellable == nil else { return @@ -314,10 +353,15 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { if governanceState.settings.value != nil { provideReferendumsIfNeeded() provideVotesIfNeeded() + provideBlockTime() metadataProvider?.refresh() } } + + func retryBlockTime() { + provideBlockTime() + } } extension ReferendumsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataLocalStorageHandler { @@ -362,6 +406,23 @@ extension ReferendumsInteractor: PriceLocalSubscriptionHandler, PriceLocalStorag } } +extension ReferendumsInteractor: GeneralLocalStorageSubscriber, GeneralLocalStorageHandler { + func handleBlockNumber(result: Result, chainId: ChainModel.Id) { + guard let chain = governanceState.settings.value, chain.chainId == chainId else { + return + } + + switch result { + case let .success(blockNumber): + if let blockNumber = blockNumber { + presenter?.didReceiveBlockNumber(blockNumber) + } + case let .failure(error): + presenter?.didReceiveError(.blockNumberSubscriptionFailed(error)) + } + } +} + extension ReferendumsInteractor: SelectedCurrencyDepending { func applyCurrency() { if presenter != nil, let chain = governanceState.settings.value { @@ -369,3 +430,9 @@ extension ReferendumsInteractor: SelectedCurrencyDepending { } } } + +extension ReferendumsInteractor: ApplicationHandlerDelegate { + func didReceiveDidEnterBackground(notification _: Notification) { + clearCancellable() + } +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 8e0125fcd7..54d1eb4d0c 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -16,6 +16,7 @@ final class ReferendumsPresenter { private var referendumsMetadata: ReferendumMetadataMapping? private var votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]? private var blockNumber: BlockNumber? + private var blockTime: BlockTime? private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() @@ -91,6 +92,10 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { interactor.refresh() } + func didReceiveBlockTime(_ blockTime: BlockTime) { + self.blockTime = blockTime + } + func didReceiveReferendums(_ referendums: [ReferendumLocal]) { self.referendums = referendums } @@ -130,10 +135,14 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { self?.interactor.refresh() } case .blockNumberSubscriptionFailed, .priceSubscriptionFailed, .balanceSubscriptionFailed, - .metadataSubscriptionFailed: + .metadataSubscriptionFailed, .blockTimeServiceFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in self?.interactor.remakeSubscriptions() } + case .blockTimeFetchFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.retryBlockTime() + } } } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index bcd128a2a2..0b71e0be24 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -15,6 +15,7 @@ protocol ReferendumsInteractorInputProtocol: AnyObject { func putOffline() func refresh() func remakeSubscriptions() + func retryBlockTime() } protocol ReferendumsInteractorOutputProtocol: AnyObject { @@ -25,6 +26,7 @@ protocol ReferendumsInteractorOutputProtocol: AnyObject { func didReceiveAssetBalance(_ balance: AssetBalance?) func didReceivePrice(_ price: PriceData?) func didReceiveBlockNumber(_ blockNumber: BlockNumber) + func didReceiveBlockTime(_ blockTime: BlockTime) func didReceiveError(_ error: ReferendumsInteractorError) } diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index 52ea3a242d..f303ef56a9 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -24,6 +24,8 @@ final class VoteChildPresenterFactory { let jsonDataProviderFactory: JsonDataProviderFactoryProtocol let priceProviderFactory: PriceProviderFactoryProtocol let applicationHandler: ApplicationHandlerProtocol + let substrateStorageFacade: StorageFacadeProtocol + let eventCenter: EventCenterProtocol let operationQueue: OperationQueue let logger: LoggerProtocol @@ -35,6 +37,8 @@ final class VoteChildPresenterFactory { priceProviderFactory: PriceProviderFactoryProtocol = PriceProviderFactory.shared, repositoryFactory: SubstrateRepositoryFactoryProtocol = SubstrateRepositoryFactory(), applicationHandler: ApplicationHandlerProtocol = ApplicationHandler(), + substrateStorageFacade: StorageFacadeProtocol = SubstrateDataStorageFacade.shared, + eventCenter: EventCenterProtocol = EventCenter.shared, operationQueue: OperationQueue = OperationManagerFacade.sharedDefaultQueue, localizationManager: LocalizationManagerProtocol = LocalizationManager.shared, logger: LoggerProtocol = Logger.shared @@ -46,6 +50,8 @@ final class VoteChildPresenterFactory { self.priceProviderFactory = priceProviderFactory self.repositoryFactory = repositoryFactory self.applicationHandler = applicationHandler + self.substrateStorageFacade = substrateStorageFacade + self.eventCenter = eventCenter self.operationQueue = operationQueue self.localizationManager = localizationManager self.logger = logger @@ -103,6 +109,21 @@ final class VoteChildPresenterFactory { let referendumOperationFactory = Gov2OperationFactory(requestFactory: requestFactory) + let serviceFactory = GovernanceServiceFactory( + chainRegisty: chainRegistry, + storageFacade: substrateStorageFacade, + eventCenter: eventCenter, + operationQueue: operationQueue, + logger: logger + ) + + let generalLocalSubscriptionFactory = GeneralStorageSubscriptionFactory( + chainRegistry: chainRegistry, + storageFacade: substrateStorageFacade, + operationManager: OperationManager(operationQueue: operationQueue), + logger: logger + ) + return ReferendumsInteractor( selectedMetaAccount: wallet, governanceState: state, @@ -110,6 +131,9 @@ final class VoteChildPresenterFactory { walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, priceLocalSubscriptionFactory: priceProviderFactory, referendumsOperationFactory: referendumOperationFactory, + generalLocalSubscriptionFactory: generalLocalSubscriptionFactory, + serviceFactory: serviceFactory, + applicationHandler: applicationHandler, operationQueue: operationQueue, currencyManager: currencyManager ) From 5657226dcf64a09e890963e038185d6d2af7cedd Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 8 Oct 2022 11:05:33 +0500 Subject: [PATCH 023/229] fix review --- novawallet/Common/Storage/GovernanceChainSettings.swift | 6 +++++- novawallet/Common/View/RoundedSegmentedControl.swift | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/novawallet/Common/Storage/GovernanceChainSettings.swift b/novawallet/Common/Storage/GovernanceChainSettings.swift index 0050182b75..4afd53fff1 100644 --- a/novawallet/Common/Storage/GovernanceChainSettings.swift +++ b/novawallet/Common/Storage/GovernanceChainSettings.swift @@ -30,6 +30,10 @@ final class GovernanceChainSettings: PersistentValueSettings { mutex.unlock() } + guard let strongSelf = self else { + return + } + let chains: [ChainModel] = changes.allChangedItems() guard !chains.isEmpty, !completed else { @@ -38,7 +42,7 @@ final class GovernanceChainSettings: PersistentValueSettings { completed = true - self?.completeSetup(for: chains, currentChainId: maybeChainId, completionClosure: completionClosure) + strongSelf.completeSetup(for: chains, currentChainId: maybeChainId, completionClosure: completionClosure) } } diff --git a/novawallet/Common/View/RoundedSegmentedControl.swift b/novawallet/Common/View/RoundedSegmentedControl.swift index 6894578963..3afff8ae08 100644 --- a/novawallet/Common/View/RoundedSegmentedControl.swift +++ b/novawallet/Common/View/RoundedSegmentedControl.swift @@ -114,7 +114,7 @@ class RoundedSegmentedControl: UIControl { configure() } - func configure() { + private func configure() { backgroundColor = UIColor.clear addSubview(backgroundView) From ba65fedb4e29d8dfee6a4af55ee94def0f24e263 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 8 Oct 2022 11:34:38 +0500 Subject: [PATCH 024/229] make switch control to work view beginTracking --- .../Common/View/RoundedSegmentedControl.swift | 33 ++++++++++++------- .../Referendums/ReferendumsInteractor.swift | 3 +- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/novawallet/Common/View/RoundedSegmentedControl.swift b/novawallet/Common/View/RoundedSegmentedControl.swift index 3afff8ae08..1e244048f4 100644 --- a/novawallet/Common/View/RoundedSegmentedControl.swift +++ b/novawallet/Common/View/RoundedSegmentedControl.swift @@ -84,6 +84,7 @@ class RoundedSegmentedControl: UIControl { view.shadowOpacity = 0 view.fillColor = .gray view.cornerRadius = 12.0 + view.isUserInteractionEnabled = false return view }() @@ -163,15 +164,11 @@ class RoundedSegmentedControl: UIControl { segmentLabel.backgroundColor = .clear segmentLabel.textAlignment = .center segmentLabel.text = title - segmentLabel.isUserInteractionEnabled = true addSubview(segmentLabel) applyStyle(for: segmentLabel, at: index) segments.append(segmentLabel) - - let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapSegment(_:))) - segmentLabel.addGestureRecognizer(tapRecognizer) } } @@ -257,15 +254,29 @@ class RoundedSegmentedControl: UIControl { // MARK: Action Handlers - @objc private func didTapSegment(_ tapRecognizer: UITapGestureRecognizer) { - if let newIndex = segments.firstIndex(where: { $0 === tapRecognizer.view }), _selectedSegmentIndex != newIndex { - let oldIndex = _selectedSegmentIndex - _selectedSegmentIndex = newIndex + override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { + let shouldBeginTracking = super.beginTracking(touch, with: event) - animateSelectionIndexChange(oldIndex) - updateSegmentsSelection() + guard case .began = touch.phase else { + return shouldBeginTracking + } + + let location = touch.location(in: self) - sendActions(for: .valueChanged) + guard + let newIndex = segments.firstIndex(where: { $0.frame.contains(location) }), + selectedSegmentIndex != newIndex else { + return shouldBeginTracking } + + let oldIndex = _selectedSegmentIndex + _selectedSegmentIndex = newIndex + + animateSelectionIndexChange(oldIndex) + updateSegmentsSelection() + + sendActions(for: .valueChanged) + + return shouldBeginTracking } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index b98806cb51..cf1e5f9ea1 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -60,7 +60,8 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani } deinit { - clear() + clearBlockTimeService() + clearCancellable() } private func clear() { From 4e531d9cfb90a8b8eba8249d2922ea64f2c9002c Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 10 Oct 2022 11:58:59 +0500 Subject: [PATCH 025/229] fetch all voters for referendum --- novawallet.xcodeproj/project.pbxproj | 4 + .../ConvictionVoting/ConvictionVoting.swift | 21 +++++ .../Model/ReferendumAccountVoteLocal.swift | 88 ++++++++++++++----- .../Governance/Model/ReferendumLocal.swift | 1 + .../Model/ReferendumVoterLocal.swift | 6 ++ .../Operation/Gov2LocalMappingFactory.swift | 28 ++++-- .../Operation/Gov2OperationFactory.swift | 50 ++++++++++- .../GovernanceOperationProtocols.swift | 8 +- .../Referendums/ReferendumsInteractor.swift | 2 +- .../Gov2OperationFactoryTests.swift | 52 ++++++++++- 10 files changed, 227 insertions(+), 33 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumVoterLocal.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 03ce5018d9..5c6526abc6 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1414,6 +1414,7 @@ 8496ADDA276AFF4600306B24 /* DAppBrowserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8496ADD9276AFF4600306B24 /* DAppBrowserScript.swift */; }; 8496ADDE276B123200306B24 /* PolkadotExtentionMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8496ADDD276B123200306B24 /* PolkadotExtentionMessage.swift */; }; 8496ADE0276B152500306B24 /* NSDictionary+Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8496ADDF276B152500306B24 /* NSDictionary+Map.swift */; }; + 849707A128F3E0AC00DD0A02 /* ReferendumVoterLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849707A028F3E0AC00DD0A02 /* ReferendumVoterLocal.swift */; }; 8497FC6026317783002FEAA7 /* AccountInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8497FC5F26317783002FEAA7 /* AccountInfoViewModel.swift */; }; 84981CC32666D95F00C4C691 /* GradientButton+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84981CC22666D95F00C4C691 /* GradientButton+Style.swift */; }; 849842E626587573006BBB9F /* MultilineTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849842E526587573006BBB9F /* MultilineTableViewCell.swift */; }; @@ -4220,6 +4221,7 @@ 8496ADD9276AFF4600306B24 /* DAppBrowserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserScript.swift; sourceTree = ""; }; 8496ADDD276B123200306B24 /* PolkadotExtentionMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotExtentionMessage.swift; sourceTree = ""; }; 8496ADDF276B152500306B24 /* NSDictionary+Map.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSDictionary+Map.swift"; sourceTree = ""; }; + 849707A028F3E0AC00DD0A02 /* ReferendumVoterLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoterLocal.swift; sourceTree = ""; }; 8497FC5F26317783002FEAA7 /* AccountInfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountInfoViewModel.swift; sourceTree = ""; }; 84981CC22666D95F00C4C691 /* GradientButton+Style.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GradientButton+Style.swift"; sourceTree = ""; }; 849842E526587573006BBB9F /* MultilineTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineTableViewCell.swift; sourceTree = ""; }; @@ -11025,6 +11027,7 @@ 84E9A04F28F000AB00551DC4 /* ReferendumMetadataLocal.swift */, 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */, 841221A528F13BA100715C82 /* GovernanceServiceFactory.swift */, + 849707A028F3E0AC00DD0A02 /* ReferendumVoterLocal.swift */, ); path = Model; sourceTree = ""; @@ -14719,6 +14722,7 @@ 842A738427DDF55A006EE1EA /* OperationIdOptionsPresentable.swift in Sources */, 849013E224A9288B008F705E /* Language.swift in Sources */, 840D92A1278D8D6F0007B979 /* DAppBrowserStateError.swift in Sources */, + 849707A128F3E0AC00DD0A02 /* ReferendumVoterLocal.swift in Sources */, 84754C882510BAFE00854599 /* ModalAlertFactory.swift in Sources */, 8430AACC2602249B005B1066 /* InitialStakingState.swift in Sources */, 84EE2FA52891205500A98816 /* WalletManageViewController.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index d50244ff8d..4c9b0a4639 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -43,6 +43,27 @@ enum ConvictionVoting { return nil } } + + var decimalValue: Decimal? { + switch self { + case .none: + return 0.1 + case .locked1x: + return 1 + case .locked2x: + return 2 + case .locked3x: + return 4 + case .locked4x: + return 8 + case .locked5x: + return 16 + case .locked6x: + return 32 + case .unknown: + return nil + } + } } struct Vote: Decodable { diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift index 2cb5ae846e..e4bce153cd 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift @@ -1,38 +1,80 @@ import Foundation import BigInt -struct ReferendumAccountVoteLocal { +enum ReferendumAccountVoteLocal { + case split(ConvictionVoting.AccountVoteSplit) + case standard(ConvictionVoting.AccountVoteStandard) + /// post conviction votes for referendum - let ayes: BigUInt - let nays: BigUInt + var ayes: BigUInt { + switch self { + case let .split(value): + return value.aye + case let .standard(value): + if value.vote.aye { + return value.vote.conviction.votes(for: value.balance) ?? 0 + } else { + return 0 + } + } + } - init?(accountVote: ConvictionVoting.AccountVote) { - switch accountVote { - case let .split(split): - self.init(accountVoteSplit: split) - case let .standard(standard): - self.init(accountVoteStandard: standard) - case .unknown: - return nil + var nays: BigUInt { + switch self { + case let .split(value): + return value.nay + case let .standard(value): + if !value.vote.aye { + return value.vote.conviction.votes(for: value.balance) ?? 0 + } else { + return 0 + } } } - init(accountVoteSplit: ConvictionVoting.AccountVoteSplit) { - ayes = accountVoteSplit.aye - nays = accountVoteSplit.nay + var ayeBalance: BigUInt { + switch self { + case let .split(value): + return value.aye + case let .standard(value): + if value.vote.aye { + return value.balance + } else { + return 0 + } + } } - init?(accountVoteStandard: ConvictionVoting.AccountVoteStandard) { - guard let votes = accountVoteStandard.vote.conviction.votes(for: accountVoteStandard.balance) else { - return nil + var nayBalance: BigUInt { + switch self { + case let .split(value): + return value.nay + case let .standard(value): + if !value.vote.aye { + return value.balance + } else { + return 0 + } } + } - if accountVoteStandard.vote.aye { - ayes = votes - nays = 0 - } else { - ayes = 0 - nays = votes + var conviction: Decimal? { + switch self { + case .split: + return 1 + case let .standard(value): + return value.vote.conviction.decimalValue + } + } + + init?(accountVote: ConvictionVoting.AccountVote) { + switch accountVote { + case let .split(split): + self = .split(split) + case let .standard(standard): + self = .standard(standard) + case .unknown: + return nil } } } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index c4b68fed61..f3e38473ba 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -4,6 +4,7 @@ import BigInt struct ReferendumLocal { let index: UInt let state: ReferendumStateLocal + let proposer: AccountId? } struct SupportAndVotesLocal { diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumVoterLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumVoterLocal.swift new file mode 100644 index 0000000000..daee93509c --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumVoterLocal.swift @@ -0,0 +1,6 @@ +import Foundation + +struct ReferendumVoterLocal { + let accountId: AccountId + let vote: ReferendumAccountVoteLocal +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index d573dfdbdb..6e83c8b727 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -96,7 +96,7 @@ final class Gov2LocalMappingFactory { ) } - return ReferendumLocal(index: UInt(index), state: state) + return ReferendumLocal(index: UInt(index), state: state, proposer: status.submissionDeposit.who) } func mapRemote( @@ -110,15 +110,31 @@ final class Gov2LocalMappingFactory { return createOngoingReferendumState(from: status, index: index, additionalInfo: additionalInfo) case let .approved(status): let model = ReferendumStateLocal.Approved(since: status.since, whenEnactment: enactmentBlock) - return ReferendumLocal(index: UInt(index), state: .approved(model: model)) + return ReferendumLocal( + index: UInt(index), + state: .approved(model: model), + proposer: status.submissionDeposit.who + ) case let .rejected(status): - return ReferendumLocal(index: UInt(index), state: .rejected(atBlock: status.since)) + return ReferendumLocal( + index: UInt(index), + state: .rejected(atBlock: status.since), + proposer: status.submissionDeposit.who + ) case let .timedOut(status): - return ReferendumLocal(index: UInt(index), state: .timedOut(atBlock: status.since)) + return ReferendumLocal( + index: UInt(index), + state: .timedOut(atBlock: status.since), + proposer: status.submissionDeposit.who + ) case let .cancelled(status): - return ReferendumLocal(index: UInt(index), state: .cancelled(atBlock: status.since)) + return ReferendumLocal( + index: UInt(index), + state: .cancelled(atBlock: status.since), + proposer: status.submissionDeposit.who + ) case let .killed(atBlock): - return ReferendumLocal(index: UInt(index), state: .killed(atBlock: atBlock)) + return ReferendumLocal(index: UInt(index), state: .killed(atBlock: atBlock), proposer: nil) case .unknown: return nil } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index ab6851ae71..8d502544cc 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -213,7 +213,7 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } - func fetchAccountVotes( + func fetchAccountVotesWrapper( for accountId: AccountId, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol @@ -255,4 +255,52 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) } + + func fetchVotersWrapper( + for referendumIndex: Referenda.ReferendumIndex, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[ReferendumVoterLocal]> { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let request = UnkeyedRemoteStorageRequest(storagePath: ConvictionVoting.votingFor) + + let votesWrapper: CompoundOperationWrapper<[ConvictionVoting.VotingForKey: ConvictionVoting.Voting]> = + requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: ConvictionVoting.votingFor, + factory: { try codingFactoryOperation.extractNoCancellableResultData() } + ) + + votesWrapper.addDependency(operations: [codingFactoryOperation]) + + let mappingOperation = ClosureOperation<[ReferendumVoterLocal]> { + let votesResult = try votesWrapper.targetOperation.extractNoCancellableResultData() + + return votesResult.compactMap { keyValue in + let accountId = keyValue.key.accountId + let voting = keyValue.value + + switch voting { + case let .casting(castingVoting): + guard + let vote = castingVoting.votes.first(where: { $0.pollIndex == referendumIndex }), + let accountVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { + return nil + } + + return ReferendumVoterLocal(accountId: accountId, vote: accountVote) + case .delegating, .unknown: + return nil + } + } + } + + mappingOperation.addDependency(votesWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + votesWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } } diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift index 44a6caf88b..4969d8d0bc 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -8,9 +8,15 @@ protocol ReferendumsOperationFactoryProtocol { runtimeProvider: RuntimeProviderProtocol ) -> CompoundOperationWrapper<[ReferendumLocal]> - func fetchAccountVotes( + func fetchAccountVotesWrapper( for accountId: AccountId, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol ) -> CompoundOperationWrapper<[Referenda.ReferendumIndex: ReferendumAccountVoteLocal]> + + func fetchVotersWrapper( + for referendumIndex: Referenda.ReferendumIndex, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[ReferendumVoterLocal]> } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index cf1e5f9ea1..33daca51f2 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -272,7 +272,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani return } - let wrapper = referendumsOperationFactory.fetchAccountVotes( + let wrapper = referendumsOperationFactory.fetchAccountVotesWrapper( for: accountId, from: connection, runtimeProvider: runtimeProvider diff --git a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift index 6e8c880d93..f6a3c50b93 100644 --- a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift +++ b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift @@ -76,7 +76,11 @@ class Gov2OperationFactoryTests: XCTestCase { let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) - let wrapper = operationFactory.fetchAccountVotes(for: accountId, from: connection, runtimeProvider: runtimeProvider) + let wrapper = operationFactory.fetchAccountVotesWrapper( + for: accountId, + from: connection, + runtimeProvider: runtimeProvider + ) operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: true) @@ -89,4 +93,50 @@ class Gov2OperationFactoryTests: XCTestCase { XCTFail("Unexpected error: \(error)") } } + + func testVotersFetch() throws { + // given + + let storageFacade = SubstrateStorageTestFacade() + let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) + let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" + let referendumIndex: Referenda.ReferendumIndex = 0 + let operationQueue = OperationQueue() + + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + guard let connection = chainRegistry.getConnection(for: chainId) else { + XCTFail("Can't get connection for chain id \(chainId)") + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + XCTFail("Can't get runtime provider for chain id \(chainId)") + return + } + + // when + + let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) + + let wrapper = operationFactory.fetchVotersWrapper( + for: referendumIndex, + from: connection, + runtimeProvider: runtimeProvider + ) + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: true) + + // then + + do { + let votes = try wrapper.targetOperation.extractNoCancellableResultData() + Logger.shared.info("Voters: \(votes)") + } catch { + XCTFail("Unexpected error: \(error)") + } + } } From 560dc12a2e464da4bc752609d63d99fba520f5ff Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 11 Oct 2022 14:11:35 +0500 Subject: [PATCH 026/229] add action details fetch logic --- novawallet.xcodeproj/project.pbxproj | 108 +++++++- .../Substrate/Types/Preimage/Preimage.swift | 24 ++ .../Preimage/PreimageRequestStatus.swift | 45 ++++ .../Types/Referenda/ReferendumInfo.swift | 2 +- .../Types/Support/SupportPallet.swift | 39 +++ .../Types/Treasury/Treasury+Calls.swift | 26 ++ .../Types/Treasury/Treasury+CodingPath.swift | 7 + .../Substrate/Types/Treasury/Treasury.swift | 5 + .../Types/Treasury/TreasuryProposal.swift | 11 + .../Model/ReferendumActionLocal.swift | 13 + .../Governance/Model/ReferendumLocal.swift | 14 ++ .../Gov2ActionOperationFactory.swift | 232 ++++++++++++++++++ .../Operation/Gov2LocalMappingFactory.swift | 2 + .../GovernanceOperationProtocols.swift | 8 + .../ReferendumDetailsInteractor.swift | 7 + .../ReferendumDetailsPresenter.swift | 21 ++ .../ReferendumDetailsProtocols.swift | 11 + .../ReferendumDetailsViewController.swift | 29 +++ .../ReferendumDetailsViewFactory.swift | 42 ++++ .../ReferendumDetailsViewLayout.swift | 12 + .../ReferendumDetailsWireframe.swift | 3 + .../Gov2OperationFactoryTests.swift | 143 ++++++----- 22 files changed, 730 insertions(+), 74 deletions(-) create mode 100644 novawallet/Common/Substrate/Types/Preimage/Preimage.swift create mode 100644 novawallet/Common/Substrate/Types/Preimage/PreimageRequestStatus.swift create mode 100644 novawallet/Common/Substrate/Types/Support/SupportPallet.swift create mode 100644 novawallet/Common/Substrate/Types/Treasury/Treasury+Calls.swift create mode 100644 novawallet/Common/Substrate/Types/Treasury/Treasury+CodingPath.swift create mode 100644 novawallet/Common/Substrate/Types/Treasury/Treasury.swift create mode 100644 novawallet/Common/Substrate/Types/Treasury/TreasuryProposal.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 5c6526abc6..0146a3f32d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 09A6D92CE47636723DFC91F4 /* MessageSheetViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57535268534B154B42ED51CE /* MessageSheetViewFactory.swift */; }; 0AAFEFA17F249F4BEF051F6B /* ControllerAccountConfirmationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54FB887490A8B33890B4E0E4 /* ControllerAccountConfirmationPresenter.swift */; }; 0B2B9C6E2BA2E924D6A54F4B /* CrowdloanListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E78D69E8EBC3EB4D01F8EF /* CrowdloanListInteractor.swift */; }; + 0B48B02E973CB304B765BBC9 /* ReferendumDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ABAD23C0039AFA8351C650 /* ReferendumDetailsProtocols.swift */; }; 0C2AA829B5CB89B39E0FA95E /* CrowdloanContributionConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF01941105BCD02536538362 /* CrowdloanContributionConfirmProtocols.swift */; }; 0CA307BC2F570941CD22C9AA /* ExportMnemonicConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4688AF0658F8BB7A90C2BE /* ExportMnemonicConfirmViewFactory.swift */; }; 0CD1F4D100ED82D137AB9834 /* ParaStkStakeSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2F1EEBF48485F02BF690A4 /* ParaStkStakeSetupViewController.swift */; }; @@ -53,6 +54,7 @@ 187C300E406092FA5F682A61 /* LedgerPerformOperationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FD612D8F897463726CDD033 /* LedgerPerformOperationViewController.swift */; }; 19A29027666EB5388CBFAD61 /* StakingRewardDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D613E20E96E7BA5B8F4B9799 /* StakingRewardDetailsInteractor.swift */; }; 19D3739A3C7800A5A18DA41C /* LedgerNetworkSelectionInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56C015A20B918DF75C499FFF /* LedgerNetworkSelectionInteractor.swift */; }; + 1A029717AD309487B70FFD02 /* ReferendumDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2F90150AD2DD3CDF7F4EDA /* ReferendumDetailsViewFactory.swift */; }; 1B1402BB29CFF6D9FB944B2D /* CreateWatchOnlyViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9DD724F02DA0A174D875A8 /* CreateWatchOnlyViewLayout.swift */; }; 1BEADE77C6236CB3BF719A47 /* CrowdloanContributionSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C96E41F878ED0A0A6F469D3 /* CrowdloanContributionSetupViewFactory.swift */; }; 1BFC90E1D8646F7429FFD5E6 /* ExportMnemonicProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF3AD755B2B3DCFB3D14DF91 /* ExportMnemonicProtocols.swift */; }; @@ -137,6 +139,7 @@ 3250F2C0E12ED42A355853BE /* SelectValidatorsStartProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED9939B17C4224C8E153F8A /* SelectValidatorsStartProtocols.swift */; }; 3349B35F5D5DDD2D46FF2E48 /* LedgerInstructionsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1F9B478321689D963F51C4E /* LedgerInstructionsViewFactory.swift */; }; 33B0D1D29AB3FC3CA23567B6 /* LedgerWalletAccountConfirmationWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEC8CCF0671304A658AD606 /* LedgerWalletAccountConfirmationWireframe.swift */; }; + 3403F3DCDE932B9F9C6D32B6 /* ReferendumDetailsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1565588CB7E044C02B091FB /* ReferendumDetailsViewLayout.swift */; }; 340AC2484415B10F247C135E /* AnalyticsValidatorsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7320E1CD9EA1A33EA29D0700 /* AnalyticsValidatorsPresenter.swift */; }; 352B75BEB10A48CC6CE64D4A /* Pods_novawalletAll_novawallet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1313BBDD3A28AC9786B5B00E /* Pods_novawalletAll_novawallet.framework */; }; 355476A5AECD2FFE4ED3DE39 /* MessageSheetViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A719A9FC28373296AB195CB /* MessageSheetViewLayout.swift */; }; @@ -181,6 +184,7 @@ 454D41CC5C7CC2FDAB778026 /* CreateWatchOnlyInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D9C85AB0C9D53B522DCF3C5 /* CreateWatchOnlyInteractor.swift */; }; 47FA7B2E0D9A87E694DA9217 /* LedgerAccountConfirmationProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E4D8E59F0976D412FF0B10 /* LedgerAccountConfirmationProtocols.swift */; }; 487A912B697604FE3367FAEC /* CrowdloanYourContributionsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FDF20DCECDEA61E1BDE780B /* CrowdloanYourContributionsViewLayout.swift */; }; + 488E4467895040EA85FDCC79 /* ReferendumDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B727587201B9D6F91A28428A /* ReferendumDetailsViewController.swift */; }; 48D5EFA462A597368024E9ED /* DAppAuthSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97612D61A441A32665C51D23 /* DAppAuthSettingsViewController.swift */; }; 493A9637BE5A1BF4B0744A4C /* ChangeWatchOnlyInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E4CD58A9006CEB045E8977 /* ChangeWatchOnlyInteractor.swift */; }; 4A520B7081BE2D7604B69354 /* AccountImportWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85F45A5C6145F863760F4409 /* AccountImportWireframe.swift */; }; @@ -219,6 +223,7 @@ 5B54978244C37502DD592486 /* NftListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A092ADC09DA0429548EBC08 /* NftListPresenter.swift */; }; 5C796EF8ED29F564B5D1126B /* CrowdloanContributionConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F75722D2F921FD1C2D4105D /* CrowdloanContributionConfirmViewController.swift */; }; 5DDD2206DF795CF205610455 /* AccountExportPasswordPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31226053044986BC828AA912 /* AccountExportPasswordPresenter.swift */; }; + 5E3B1E6B9E94848B186FD4D1 /* ReferendumDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AC65A04352405327BFE946 /* ReferendumDetailsInteractor.swift */; }; 5E621A350A6DDD78597CC9E5 /* CrowdloanYourContributionsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38A4CCD27081CF017AFCD18 /* CrowdloanYourContributionsWireframe.swift */; }; 5E6D69D84220119BA5362358 /* OperationDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F2670E15D23CF30931389E3 /* OperationDetailsProtocols.swift */; }; 5FD7B3463822BC69AF5E3C72 /* ParaStkUnstakeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F711415F7C805D43E83644C6 /* ParaStkUnstakeViewController.swift */; }; @@ -288,6 +293,7 @@ 7C93FA82996A426E7B8CA06E /* AccountExportPasswordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D5AF2F7609ADE855308089 /* AccountExportPasswordViewController.swift */; }; 7CBE9FFAF8394786CA131D4D /* CustomValidatorListProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F28EDDF9277242505FDDECA1 /* CustomValidatorListProtocols.swift */; }; 7D281FEA78E2E5F44990C184 /* AccountImportPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB8605FD90D8C3553A9897B4 /* AccountImportPresenter.swift */; }; + 7D2906130F25492872637EFC /* ReferendumDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78536852751EF56F58C5691E /* ReferendumDetailsPresenter.swift */; }; 7D707DDD180999C63FD0C4ED /* AssetListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE26599B4E43DC4CE520528 /* AssetListViewController.swift */; }; 7D7D40581C276D60713822E9 /* ParaStkCollatorFiltersPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39503B664F159E5D07FF6281 /* ParaStkCollatorFiltersPresenter.swift */; }; 7E1A03082260E0D31AD394CA /* StakingRewardDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF891BE39D442C2D06DDF3BB /* StakingRewardDetailsProtocols.swift */; }; @@ -894,6 +900,13 @@ 8459A9C827469E4B000D6278 /* AcalaContributionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8459A9C727469E4B000D6278 /* AcalaContributionSource.swift */; }; 8459A9CA2746A1BC000D6278 /* CrowdloanOffchainSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8459A9C92746A1BC000D6278 /* CrowdloanOffchainSubscriber.swift */; }; 8459A9CC2746A1E9000D6278 /* CrowdloanOffchainSubscriptionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8459A9CB2746A1E9000D6278 /* CrowdloanOffchainSubscriptionHandler.swift */; }; + 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811128F429BB0040CE84 /* SupportPallet.swift */; }; + 845B811528F43C350040CE84 /* Treasury.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811428F43C350040CE84 /* Treasury.swift */; }; + 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811628F43C730040CE84 /* TreasuryProposal.swift */; }; + 845B811928F43D4C0040CE84 /* Treasury+CodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811828F43D4C0040CE84 /* Treasury+CodingPath.swift */; }; + 845B811B28F445E90040CE84 /* Treasury+Calls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811A28F445E90040CE84 /* Treasury+Calls.swift */; }; + 845B811D28F44A700040CE84 /* ReferendumActionLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811C28F44A700040CE84 /* ReferendumActionLocal.swift */; }; + 845B811F28F451A40040CE84 /* Gov2ActionOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */; }; 845B821526EF657700D25C72 /* PersistentValueSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B821426EF657700D25C72 /* PersistentValueSettings.swift */; }; 845B821726EF7FED00D25C72 /* SelectedWalletSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B821626EF7FED00D25C72 /* SelectedWalletSettings.swift */; }; 845B821926EF808D00D25C72 /* MetaAccountMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B821826EF808D00D25C72 /* MetaAccountMapper.swift */; }; @@ -1570,6 +1583,8 @@ 84B5DE53283F7BE500193ED3 /* CollatorsSortType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B5DE52283F7BE500193ED3 /* CollatorsSortType.swift */; }; 84B5DE56283F7C8500193ED3 /* CollatorSelectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B5DE55283F7C8500193ED3 /* CollatorSelectionCell.swift */; }; 84B5DE59283F8B5400193ED3 /* CollatorSelectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B5DE58283F8B5400193ED3 /* CollatorSelectionViewModel.swift */; }; + 84B6349D28F4A06D00503306 /* Preimage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B6349C28F4A06D00503306 /* Preimage.swift */; }; + 84B6349F28F5575900503306 /* PreimageRequestStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B6349E28F5575900503306 /* PreimageRequestStatus.swift */; }; 84B64E3F2704567700914E88 /* StakingLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B64E3E2704567700914E88 /* StakingLocalStorageSubscriber.swift */; }; 84B64E412704569D00914E88 /* StakingLocalSubscriptionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B64E402704569D00914E88 /* StakingLocalSubscriptionHandler.swift */; }; 84B66A0B26FDB70F0038B963 /* CrowdloansListInteractor+Protocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B66A0A26FDB70F0038B963 /* CrowdloansListInteractor+Protocols.swift */; }; @@ -2469,6 +2484,7 @@ C46EEF6A9A9A601694E72DB1 /* StakingMainWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F09665083031502F9693F8 /* StakingMainWireframe.swift */; }; C4A4D40A08DAB4A71C21C1A8 /* StakingRedeemInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560C48D7A83F51F001622D71 /* StakingRedeemInteractor.swift */; }; C5B6C00F8B0E3D89CBF1A8DB /* ParaStkSelectCollatorsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2336E4CAF4A1F627C39093FF /* ParaStkSelectCollatorsViewFactory.swift */; }; + C644308270C29AC6F90CFEA6 /* ReferendumDetailsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2EB9EE4A87BD4A74040784 /* ReferendumDetailsWireframe.swift */; }; C6E5671768DA68535DA5B1C7 /* ControllerAccountConfirmationViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F02DBCA4A63A5E52E3739374 /* ControllerAccountConfirmationViewFactory.swift */; }; C729BF3E60E6825AEED11383 /* ParaStkRedeemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AD16D5FA4115F2A525BDE4F /* ParaStkRedeemViewController.swift */; }; C74B44F382EDAE5CB5A8468F /* ParaStkUnstakeConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C973B203F72D6233718CD4 /* ParaStkUnstakeConfirmProtocols.swift */; }; @@ -3019,6 +3035,7 @@ 5C96E41F878ED0A0A6F469D3 /* CrowdloanContributionSetupViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupViewFactory.swift; sourceTree = ""; }; 5CD36AD8C414F8973CDA8A0F /* ParaStkUnstakeConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeConfirmViewLayout.swift; sourceTree = ""; }; 5D0E02AA5D3EBA9B94950241 /* SelectValidatorsConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmWireframe.swift; sourceTree = ""; }; + 5E2EB9EE4A87BD4A74040784 /* ReferendumDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsWireframe.swift; sourceTree = ""; }; 5EAF3AEE27F7901458B39A7A /* Pods-novawalletAll-novawalletIntegrationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-novawalletAll-novawalletIntegrationTests.debug.xcconfig"; path = "Target Support Files/Pods-novawalletAll-novawalletIntegrationTests/Pods-novawalletAll-novawalletIntegrationTests.debug.xcconfig"; sourceTree = ""; }; 5F4F3C080F3D5C1E64475903 /* ParitySignerAddressesProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddressesProtocols.swift; sourceTree = ""; }; 5F791FE1B479CE1DF936F79F /* CrowdloanContributionConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmViewFactory.swift; sourceTree = ""; }; @@ -3066,6 +3083,7 @@ 76AA6A6232B1CF2D5AF74D0D /* ParaStkUnstakeInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeInteractor.swift; sourceTree = ""; }; 781FA4C896AF31B4035AFB38 /* ChainAddressDetailsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainAddressDetailsViewFactory.swift; sourceTree = ""; }; 782CC21A2F9EEF5DBA3AB1AA /* PurchaseProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PurchaseProtocols.swift; sourceTree = ""; }; + 78536852751EF56F58C5691E /* ReferendumDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsPresenter.swift; sourceTree = ""; }; 7859654B7C1FAC269CA61E71 /* ParitySignerTxQrInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerTxQrInteractor.swift; sourceTree = ""; }; 78670B0926E92B75088D2D7B /* WalletHistoryFilterWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletHistoryFilterWireframe.swift; sourceTree = ""; }; 78A5A3C9077FCE262224B832 /* ParaStkYieldBoostSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostSetupInteractor.swift; sourceTree = ""; }; @@ -3693,6 +3711,13 @@ 8459A9C727469E4B000D6278 /* AcalaContributionSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcalaContributionSource.swift; sourceTree = ""; }; 8459A9C92746A1BC000D6278 /* CrowdloanOffchainSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanOffchainSubscriber.swift; sourceTree = ""; }; 8459A9CB2746A1E9000D6278 /* CrowdloanOffchainSubscriptionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanOffchainSubscriptionHandler.swift; sourceTree = ""; }; + 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; + 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; + 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; + 845B811828F43D4C0040CE84 /* Treasury+CodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Treasury+CodingPath.swift"; sourceTree = ""; }; + 845B811A28F445E90040CE84 /* Treasury+Calls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Treasury+Calls.swift"; sourceTree = ""; }; + 845B811C28F44A700040CE84 /* ReferendumActionLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumActionLocal.swift; sourceTree = ""; }; + 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2ActionOperationFactory.swift; sourceTree = ""; }; 845B821426EF657700D25C72 /* PersistentValueSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentValueSettings.swift; sourceTree = ""; }; 845B821626EF7FED00D25C72 /* SelectedWalletSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedWalletSettings.swift; sourceTree = ""; }; 845B821826EF808D00D25C72 /* MetaAccountMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaAccountMapper.swift; sourceTree = ""; }; @@ -3825,7 +3850,6 @@ 846A835E28B8D94300D92892 /* MessageSheetNoContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSheetNoContentView.swift; sourceTree = ""; }; 846A836028B8DB7700D92892 /* MessageSheetTimerLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSheetTimerLabel.swift; sourceTree = ""; }; 846AACEC28BF94B9009F3D42 /* AccountManagementFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountManagementFilter.swift; sourceTree = ""; }; - 846AACEE28BF9519009F3D42 /* NoAccountSupportPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoAccountSupportPresentable.swift; sourceTree = ""; }; 846AC7EE2638D9200075F7DA /* YourValidatorTableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourValidatorTableCell.swift; sourceTree = ""; }; 846AF83D2525B85100868F37 /* WalletNetworkFacade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletNetworkFacade.swift; sourceTree = ""; }; 846AF83F2525B94D00868F37 /* WalletNetworkFacade+Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WalletNetworkFacade+Protocol.swift"; sourceTree = ""; }; @@ -4046,7 +4070,6 @@ 848A837D274BB03E004493DD /* PublicSans-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "PublicSans-Regular.otf"; sourceTree = ""; }; 848B2FFD286EDA4700465BA2 /* WalletServiceFacade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletServiceFacade.swift; sourceTree = ""; }; 848B2FFF286EDE3800465BA2 /* ParaIdOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParaIdOperationFactory.swift; sourceTree = ""; }; - 848B59B328BC9FBF0009543C /* AccountManagementFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountManagementFilter.swift; sourceTree = ""; }; 848B59B928BCB3CA0009543C /* LedgerBaseAccountConfirmationWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LedgerBaseAccountConfirmationWireframe.swift; sourceTree = ""; }; 848B59BD28BCB4C80009543C /* LedgerAddAccountConfirmationWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LedgerAddAccountConfirmationWireframe.swift; sourceTree = ""; }; 848B59BF28BCB8530009543C /* LedgerBaseAccountConfirmationInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LedgerBaseAccountConfirmationInteractor.swift; sourceTree = ""; }; @@ -4377,6 +4400,8 @@ 84B5DE52283F7BE500193ED3 /* CollatorsSortType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollatorsSortType.swift; sourceTree = ""; }; 84B5DE55283F7C8500193ED3 /* CollatorSelectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollatorSelectionCell.swift; sourceTree = ""; }; 84B5DE58283F8B5400193ED3 /* CollatorSelectionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollatorSelectionViewModel.swift; sourceTree = ""; }; + 84B6349C28F4A06D00503306 /* Preimage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preimage.swift; sourceTree = ""; }; + 84B6349E28F5575900503306 /* PreimageRequestStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreimageRequestStatus.swift; sourceTree = ""; }; 84B64E3E2704567700914E88 /* StakingLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingLocalStorageSubscriber.swift; sourceTree = ""; }; 84B64E402704569D00914E88 /* StakingLocalSubscriptionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingLocalSubscriptionHandler.swift; sourceTree = ""; }; 84B66A0A26FDB70F0038B963 /* CrowdloansListInteractor+Protocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CrowdloansListInteractor+Protocols.swift"; sourceTree = ""; }; @@ -5092,11 +5117,13 @@ 9D93D6B6DB7BACFEA6F2738C /* ParaStkCollatorInfoInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorInfoInteractor.swift; sourceTree = ""; }; 9DBACA1AB17E90565F133C19 /* WalletsListInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletsListInteractor.swift; sourceTree = ""; }; 9F1BCCE09BB15106FDC02495 /* ParaStkRebondInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRebondInteractor.swift; sourceTree = ""; }; + 9F2F90150AD2DD3CDF7F4EDA /* ReferendumDetailsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsViewFactory.swift; sourceTree = ""; }; 9FDF20DCECDEA61E1BDE780B /* CrowdloanYourContributionsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanYourContributionsViewLayout.swift; sourceTree = ""; }; A028BD1A81CA95BE0DB66031 /* DAppTxDetailsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsViewFactory.swift; sourceTree = ""; }; A0F285548A6F98B3EB3F170C /* NftDetailsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftDetailsViewLayout.swift; sourceTree = ""; }; A12FACE9CF804AF777024A31 /* ParitySignerAddressesViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddressesViewFactory.swift; sourceTree = ""; }; A14CA4551FCC2EBD078E2242 /* AccountConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountConfirmViewFactory.swift; sourceTree = ""; }; + A1565588CB7E044C02B091FB /* ReferendumDetailsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsViewLayout.swift; sourceTree = ""; }; A2AEC47F0599E0AC45237639 /* Pods-novawalletAll-novawallet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-novawalletAll-novawallet.release.xcconfig"; path = "Target Support Files/Pods-novawalletAll-novawallet/Pods-novawalletAll-novawallet.release.xcconfig"; sourceTree = ""; }; A3104ABC4BECF08B0BA836AA /* AccountConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountConfirmViewController.swift; sourceTree = ""; }; A31780E84948D7FE632ECB02 /* YourValidatorListProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourValidatorListProtocols.swift; sourceTree = ""; }; @@ -5260,6 +5287,7 @@ B56202207DF8BB6684C6EF6C /* AdvancedWalletPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AdvancedWalletPresenter.swift; sourceTree = ""; }; B5BC1402B34E341312ABB378 /* LedgerWalletConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerWalletConfirmPresenter.swift; sourceTree = ""; }; B6884DFC1AA1B995C21C274C /* WalletHistoryFilterViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletHistoryFilterViewController.swift; sourceTree = ""; }; + B727587201B9D6F91A28428A /* ReferendumDetailsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsViewController.swift; sourceTree = ""; }; B765BDAA27726E2586953368 /* OnChainTransferSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OnChainTransferSetupInteractor.swift; sourceTree = ""; }; B7CB6BF970620958C9DDD037 /* ParaStkStakeConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkStakeConfirmWireframe.swift; sourceTree = ""; }; B8A6C6207095F63972E14618 /* DAppPhishingProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppPhishingProtocols.swift; sourceTree = ""; }; @@ -5281,6 +5309,7 @@ C1B08ACC71BE679A48A7B66E /* LedgerInstructionsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerInstructionsPresenter.swift; sourceTree = ""; }; C22DAB1222A253F4ADAD9169 /* ParaStkYieldBoostSetupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostSetupViewController.swift; sourceTree = ""; }; C2956D0C69019DDCDAB2EB34 /* CustomValidatorListViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CustomValidatorListViewLayout.swift; sourceTree = ""; }; + C3ABAD23C0039AFA8351C650 /* ReferendumDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsProtocols.swift; sourceTree = ""; }; C503100478AB56E903598A78 /* ReferralCrowdloanPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferralCrowdloanPresenter.swift; sourceTree = ""; }; C6F8BBBA9EABA266B288333F /* AnalyticsValidatorsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsValidatorsViewFactory.swift; sourceTree = ""; }; C74A2166B054240BD5D925B6 /* UsernameSetupViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UsernameSetupViewFactory.swift; sourceTree = ""; }; @@ -5310,6 +5339,7 @@ D529B9CA8D6E2E6F375FC260 /* AssetListProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetListProtocols.swift; sourceTree = ""; }; D5840ED54B83E2C652442DBC /* ParitySignerAddConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddConfirmProtocols.swift; sourceTree = ""; }; D5A5DCA28ABF42D342BBDF9A /* ParitySignerTxQrViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerTxQrViewLayout.swift; sourceTree = ""; }; + D5AC65A04352405327BFE946 /* ReferendumDetailsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsInteractor.swift; sourceTree = ""; }; D613E20E96E7BA5B8F4B9799 /* StakingRewardDetailsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardDetailsInteractor.swift; sourceTree = ""; }; D6470B066E67834BF97E0A68 /* StakingRewardDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardDetailsPresenter.swift; sourceTree = ""; }; D6C6573C52692E4A56E35FF9 /* RecommendedValidatorListProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RecommendedValidatorListProtocols.swift; sourceTree = ""; }; @@ -7183,6 +7213,9 @@ 8438E1DC24C18F11001BDB13 /* Types */ = { isa = PBXGroup; children = ( + 84B6349B28F4A05A00503306 /* Preimage */, + 845B811328F43C1E0040CE84 /* Treasury */, + 845B811028F429AB0040CE84 /* Support */, 848CC94228D9FBBE009EB4B0 /* ConvictionVoting */, 848CC93928D9F68C009EB4B0 /* Scheduler */, 847A25C428D84BC9006AC9F5 /* Referenda */, @@ -7658,6 +7691,25 @@ path = EntityToModel; sourceTree = ""; }; + 845B811028F429AB0040CE84 /* Support */ = { + isa = PBXGroup; + children = ( + 845B811128F429BB0040CE84 /* SupportPallet.swift */, + ); + path = Support; + sourceTree = ""; + }; + 845B811328F43C1E0040CE84 /* Treasury */ = { + isa = PBXGroup; + children = ( + 845B811428F43C350040CE84 /* Treasury.swift */, + 845B811628F43C730040CE84 /* TreasuryProposal.swift */, + 845B811828F43D4C0040CE84 /* Treasury+CodingPath.swift */, + 845B811A28F445E90040CE84 /* Treasury+Calls.swift */, + ); + path = Treasury; + sourceTree = ""; + }; 845BB8B625E4464D00E5FCDC /* ExtrinsicService */ = { isa = PBXGroup; children = ( @@ -8289,6 +8341,7 @@ 84A1742528ED60610096F943 /* Operation */, 84D8753B28EB1796004065BD /* Model */, 8442002128E6FE0100C49C4A /* Referendums */, + B4F0332763AFF64A3793C679 /* ReferendumDetails */, ); path = Governance; sourceTree = ""; @@ -8588,7 +8641,6 @@ 849013A924A80984008F705E /* Products */, 2698CD398B0412EB85D620AB /* Pods */, BFB3965A583F11EF3045E064 /* Frameworks */, - 849DA43128C5D58D004757F0 /* Recovered References */, ); sourceTree = ""; }; @@ -9752,15 +9804,6 @@ path = Models; sourceTree = ""; }; - 849DA43128C5D58D004757F0 /* Recovered References */ = { - isa = PBXGroup; - children = ( - 848B59B328BC9FBF0009543C /* AccountManagementFilter.swift */, - 846AACEE28BF9519009F3D42 /* NoAccountSupportPresentable.swift */, - ); - name = "Recovered References"; - sourceTree = ""; - }; 849DEBD225ED014000C64C19 /* ViewModel */ = { isa = PBXGroup; children = ( @@ -9792,6 +9835,7 @@ 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */, 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, + 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */, ); path = Operation; sourceTree = ""; @@ -9924,6 +9968,15 @@ path = Model; sourceTree = ""; }; + 84B6349B28F4A05A00503306 /* Preimage */ = { + isa = PBXGroup; + children = ( + 84B6349C28F4A06D00503306 /* Preimage.swift */, + 84B6349E28F5575900503306 /* PreimageRequestStatus.swift */, + ); + path = Preimage; + sourceTree = ""; + }; 84B7C680289BFA78001A3566 /* Modules */ = { isa = PBXGroup; children = ( @@ -11028,6 +11081,7 @@ 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */, 841221A528F13BA100715C82 /* GovernanceServiceFactory.swift */, 849707A028F3E0AC00DD0A02 /* ReferendumVoterLocal.swift */, + 845B811C28F44A700040CE84 /* ReferendumActionLocal.swift */, ); path = Model; sourceTree = ""; @@ -12480,6 +12534,20 @@ path = DAppSearch; sourceTree = ""; }; + B4F0332763AFF64A3793C679 /* ReferendumDetails */ = { + isa = PBXGroup; + children = ( + C3ABAD23C0039AFA8351C650 /* ReferendumDetailsProtocols.swift */, + 5E2EB9EE4A87BD4A74040784 /* ReferendumDetailsWireframe.swift */, + 78536852751EF56F58C5691E /* ReferendumDetailsPresenter.swift */, + D5AC65A04352405327BFE946 /* ReferendumDetailsInteractor.swift */, + B727587201B9D6F91A28428A /* ReferendumDetailsViewController.swift */, + A1565588CB7E044C02B091FB /* ReferendumDetailsViewLayout.swift */, + 9F2F90150AD2DD3CDF7F4EDA /* ReferendumDetailsViewFactory.swift */, + ); + path = ReferendumDetails; + sourceTree = ""; + }; B7B0681CCE8F8F0127E8676C /* StakingMain */ = { isa = PBXGroup; children = ( @@ -14290,6 +14358,7 @@ 842D1E9624D2DD6700C30A7A /* MnemonicDisplayView.swift in Sources */, 8411707A285B10F5006F4DFB /* XcmAssetTransferFee.swift in Sources */, 84DBEA56265ED62700FDF73C /* BaseErrorPresentable.swift in Sources */, + 845B811928F43D4C0040CE84 /* Treasury+CodingPath.swift in Sources */, 842876B224AE059700D91AD8 /* SupportData.swift in Sources */, 84D8754228EB5D66004065BD /* ChainBalanceViewModel.swift in Sources */, 84893C0524DA8663008F6A3F /* AccountCreationError.swift in Sources */, @@ -14326,6 +14395,7 @@ 841AAC2526F692EF00F0A25E /* AddressConversion.swift in Sources */, 846F758927B5584100536547 /* EthereumRpcResponse.swift in Sources */, 8490147624A94A37008F705E /* RootInteractor.swift in Sources */, + 845B811B28F445E90040CE84 /* Treasury+Calls.swift in Sources */, 846F757E27B53F5100536547 /* DAppMetamaskSigningState.swift in Sources */, 849E17E0279094E7002D1744 /* DAppSearchHeaderView.swift in Sources */, F40966CE26B297D6008CD244 /* AnalyticsStakeProtocols.swift in Sources */, @@ -14368,6 +14438,7 @@ 8446F5FA28192FF500B7A86C /* ListLoadingView.swift in Sources */, 844384AC28538D3000611CE2 /* RewardCalculatorEngine.swift in Sources */, 84DBEA5E265EDAD300FDF73C /* BaseDataValidatorFactory.swift in Sources */, + 84B6349F28F5575900503306 /* PreimageRequestStatus.swift in Sources */, F4F69E282731B0B200214542 /* VoteTableHeaderView.swift in Sources */, 8428768624AE046300D91AD8 /* LanguageSelectionPresenter.swift in Sources */, 8490152724ABCC40008F705E /* NumberFormatter.swift in Sources */, @@ -14729,6 +14800,7 @@ 84786DA825F9F58E0089DFF7 /* EraValidatorService+Fetch.swift in Sources */, 84ACEBFF261E6C7C00AAE665 /* WalletHistoryFilterViewLayout.swift in Sources */, 846A835F28B8D94300D92892 /* MessageSheetNoContentView.swift in Sources */, + 845B811F28F451A40040CE84 /* Gov2ActionOperationFactory.swift in Sources */, 84754CA22513DB8800854599 /* EmptyAccountIcon.swift in Sources */, AEA0C8C6268131C500F9666F /* InitiatedBondingSelectedValidatorsListWireframe.swift in Sources */, 84CE69922565244700559427 /* WalletAccountOpenCommand.swift in Sources */, @@ -14804,6 +14876,7 @@ 849014DE24AA8F60008F705E /* MainTabBarInteractor.swift in Sources */, 849ABE7226280F3800011A2A /* ControllersReducer.swift in Sources */, 84F30EE425FFAC0800039D09 /* StreamableProviderOptions+Substrate.swift in Sources */, + 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */, 8470D6D4253E35F0009E9A5D /* StorageUpdate.swift in Sources */, 8460E715284AC0AA002896E9 /* ParaStkBaseUnstakeInteractor.swift in Sources */, 84C2F27D25E297350050A4AD /* CalculatedReward.swift in Sources */, @@ -14959,6 +15032,7 @@ 844AE53C2861B3BC0020ECBC /* XcmTransferService.swift in Sources */, 2A9F8D52274E4EC4003720E0 /* AccountCreateViewController.swift in Sources */, 84113B91255B2CA0009BD21A /* MainTransitionHelper.swift in Sources */, + 84B6349D28F4A06D00503306 /* Preimage.swift in Sources */, 8428768524AE046300D91AD8 /* LanguageSelectionProtocols.swift in Sources */, 2A90206E273E6CA200F2D584 /* NetworkFeeConfirmView+Protocol.swift in Sources */, AEA0C8A4267B6B1900F9666F /* SelectedValidatorListProtocols.swift in Sources */, @@ -15106,6 +15180,7 @@ 846C372E26B199D10098F303 /* BabeStakingDurationFactory.swift in Sources */, 8475AE39258B958300B058F3 /* ErrorContent+Wallet.swift in Sources */, 9B4F0484B81BBF8DFA618599 /* AccountCreateViewFactory.swift in Sources */, + 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */, 8460E718284CF124002896E9 /* ParachainStakingValidatorFactoryProtocol.swift in Sources */, 846CDECD258D212D009F3E75 /* AlertImageWithTitleView.swift in Sources */, 8419378125442FEE00CFA50C /* WalletQRCoderFactory.swift in Sources */, @@ -16002,6 +16077,7 @@ 841816712824F4F30007684A /* ParachainStakingCollatorSnapshot.swift in Sources */, 5B54978244C37502DD592486 /* NftListPresenter.swift in Sources */, 6797F109D7C270DE4877B435 /* NftListInteractor.swift in Sources */, + 845B811528F43C350040CE84 /* Treasury.swift in Sources */, 84C3420B283187D800156569 /* BlockTimeEstimationService.swift in Sources */, EB376E61CD1C39AC148DE80C /* NftListViewController.swift in Sources */, 84C5ADD02811E6FA006D7388 /* LinkCellView.swift in Sources */, @@ -16301,6 +16377,14 @@ A2BE8967FC1609D61E4131BE /* ParaStkYieldBoostStopViewController.swift in Sources */, 7584B6DC2C7F8B2B6671908F /* ParaStkYieldBoostStopViewLayout.swift in Sources */, 3E0DDDE01391F9041C8D7382 /* ParaStkYieldBoostStopViewFactory.swift in Sources */, + 0B48B02E973CB304B765BBC9 /* ReferendumDetailsProtocols.swift in Sources */, + C644308270C29AC6F90CFEA6 /* ReferendumDetailsWireframe.swift in Sources */, + 7D2906130F25492872637EFC /* ReferendumDetailsPresenter.swift in Sources */, + 5E3B1E6B9E94848B186FD4D1 /* ReferendumDetailsInteractor.swift in Sources */, + 488E4467895040EA85FDCC79 /* ReferendumDetailsViewController.swift in Sources */, + 845B811D28F44A700040CE84 /* ReferendumActionLocal.swift in Sources */, + 3403F3DCDE932B9F9C6D32B6 /* ReferendumDetailsViewLayout.swift in Sources */, + 1A029717AD309487B70FFD02 /* ReferendumDetailsViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Common/Substrate/Types/Preimage/Preimage.swift b/novawallet/Common/Substrate/Types/Preimage/Preimage.swift new file mode 100644 index 0000000000..ee0d884d78 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Preimage/Preimage.swift @@ -0,0 +1,24 @@ +import Foundation +import SubstrateSdk + +enum Preimage { + static var preimageForStoragePath: StorageCodingPath { + StorageCodingPath(moduleName: "Preimage", itemName: "PreimageFor") + } + + static var statusForStoragePath: StorageCodingPath { + StorageCodingPath(moduleName: "Preimage", itemName: "StatusFor") + } + + struct PreimageKey: Encodable { + let hash: Data + let length: UInt32 + + func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + + try container.encode(hash) + try container.encode(StringScaleMapper(value: length)) + } + } +} diff --git a/novawallet/Common/Substrate/Types/Preimage/PreimageRequestStatus.swift b/novawallet/Common/Substrate/Types/Preimage/PreimageRequestStatus.swift new file mode 100644 index 0000000000..0587fd04c5 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Preimage/PreimageRequestStatus.swift @@ -0,0 +1,45 @@ +import Foundation +import SubstrateSdk + +extension Preimage { + struct RequestStatusUnrequested: Decodable { + @StringCodable var len: UInt32 + } + + struct RequestStatusRequested: Decodable { + @OptionStringCodable var len: UInt32? + } + + enum RequestStatus: Decodable { + case unrequested(RequestStatusUnrequested) + case requested(RequestStatusRequested) + case unknown + + init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "Unrequested": + let status = try container.decode(RequestStatusUnrequested.self) + self = .unrequested(status) + case "Requested": + let status = try container.decode(RequestStatusRequested.self) + self = .requested(status) + default: + self = .unknown + } + } + + var length: UInt32? { + switch self { + case let .unrequested(requestStatusUnrequested): + return requestStatusUnrequested.len + case let .requested(requestStatusRequested): + return requestStatusRequested.len + case .unknown: + return nil + } + } + } +} diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift index 28d52bb648..edafe57090 100644 --- a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift @@ -9,7 +9,7 @@ enum ReferendumInfo: Decodable { struct OngoingStatus: Decodable { @StringCodable var track: Referenda.TrackId - @BytesCodable var proposalHash: Data + let proposal: SupportPallet.Bounded> let enactment: OnChainScheduler.DispatchTime @StringCodable var submitted: Moment let submissionDeposit: Referenda.Deposit diff --git a/novawallet/Common/Substrate/Types/Support/SupportPallet.swift b/novawallet/Common/Substrate/Types/Support/SupportPallet.swift new file mode 100644 index 0000000000..f9fdacae72 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Support/SupportPallet.swift @@ -0,0 +1,39 @@ +import Foundation +import SubstrateSdk + +enum SupportPallet { + struct BoundedLookup: Decodable { + @BytesCodable var hash: Data + @StringCodable var len: UInt32 + } + + struct BoundedLegacy: Decodable { + @BytesCodable var hash: Data + } + + enum Bounded: Decodable where T: Decodable { + case legacy(hash: Data) + case inline(value: T) + case lookup(BoundedLookup) + case unknown + + init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "Legacy": + let hash = try container.decode(BoundedLegacy.self).hash + self = .legacy(hash: hash) + case "Inline": + let value = try container.decode(T.self) + self = .inline(value: value) + case "Lookup": + let lookup = try container.decode(BoundedLookup.self) + self = .lookup(lookup) + default: + self = .unknown + } + } + } +} diff --git a/novawallet/Common/Substrate/Types/Treasury/Treasury+Calls.swift b/novawallet/Common/Substrate/Types/Treasury/Treasury+Calls.swift new file mode 100644 index 0000000000..618cc1c761 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Treasury/Treasury+Calls.swift @@ -0,0 +1,26 @@ +import Foundation +import SubstrateSdk +import BigInt + +extension Treasury { + static var approveProposalCallPath: CallCodingPath { + CallCodingPath(moduleName: "Treasury", callName: "approve_proposal") + } + + struct ApproveProposal: Decodable { + enum CodingKeys: String, CodingKey { + case proposalId = "proposal_id" + } + + @StringCodable var proposalId: ProposalIndex + } + + static var spendCallPath: CallCodingPath { + CallCodingPath(moduleName: "Treasury", callName: "spend") + } + + struct SpendCall: Decodable { + @StringCodable var amount: BigUInt + let beneficiary: AccountId + } +} diff --git a/novawallet/Common/Substrate/Types/Treasury/Treasury+CodingPath.swift b/novawallet/Common/Substrate/Types/Treasury/Treasury+CodingPath.swift new file mode 100644 index 0000000000..74a4391b7e --- /dev/null +++ b/novawallet/Common/Substrate/Types/Treasury/Treasury+CodingPath.swift @@ -0,0 +1,7 @@ +import Foundation + +extension Treasury { + static var proposalsStoragePath: StorageCodingPath { + StorageCodingPath(moduleName: "Treasury", itemName: "Proposals") + } +} diff --git a/novawallet/Common/Substrate/Types/Treasury/Treasury.swift b/novawallet/Common/Substrate/Types/Treasury/Treasury.swift new file mode 100644 index 0000000000..ec874ed279 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Treasury/Treasury.swift @@ -0,0 +1,5 @@ +import Foundation + +enum Treasury { + typealias ProposalIndex = UInt32 +} diff --git a/novawallet/Common/Substrate/Types/Treasury/TreasuryProposal.swift b/novawallet/Common/Substrate/Types/Treasury/TreasuryProposal.swift new file mode 100644 index 0000000000..4ab48ade27 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Treasury/TreasuryProposal.swift @@ -0,0 +1,11 @@ +import Foundation +import SubstrateSdk +import BigInt + +extension Treasury { + struct Proposal: Decodable { + let proposer: AccountId + @StringCodable var value: BigUInt + let beneficiary: AccountId + } +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift new file mode 100644 index 0000000000..dda83a3ebc --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift @@ -0,0 +1,13 @@ +import Foundation +import BigInt +import SubstrateSdk + +struct ReferendumActionLocal { + struct AmountSpendDetails { + let amount: BigUInt + let beneficiaryAccountId: AccountId + } + + let amountSpendDetails: AmountSpendDetails? + let call: RuntimeCall? +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index f3e38473ba..0c2c9d82f7 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -1,5 +1,6 @@ import Foundation import BigInt +import SubstrateSdk struct ReferendumLocal { let index: UInt @@ -57,6 +58,7 @@ enum ReferendumStateLocal { struct Deciding { let track: GovernanceTrackLocal + let proposal: SupportPallet.Bounded> let voting: Voting let since: BlockNumber let period: Moment @@ -65,6 +67,7 @@ enum ReferendumStateLocal { struct Preparing { let track: GovernanceTrackLocal + let proposal: SupportPallet.Bounded> let voting: Voting let deposit: BigUInt? let since: BlockNumber @@ -95,6 +98,17 @@ enum ReferendumStateLocal { return true } } + + var proposal: SupportPallet.Bounded>? { + switch self { + case let .preparing(model): + return model.proposal + case let .deciding(model): + return model.proposal + case .approved, .rejected, .cancelled, .timedOut, .killed, .executed: + return nil + } + } } struct GovernanceTrackLocal { diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift new file mode 100644 index 0000000000..11c8d879cd --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift @@ -0,0 +1,232 @@ +import Foundation +import RobinHood +import SubstrateSdk + +final class Gov2ActionOperationFactory { + static let maxFetchCallSize: UInt32 = 1024 + + let requestFactory: StorageRequestFactoryProtocol + let operationQueue: OperationQueue + + init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { + self.requestFactory = requestFactory + self.operationQueue = operationQueue + } + + private func createCallFetchWrapper( + dependingOn codingFactoryOperation: BaseOperation, + referendum: ReferendumLocal, + requestFactory: StorageRequestFactoryProtocol, + connection: JSONRPCEngine + ) -> CompoundOperationWrapper?> { + let callFetchClosure: (Data) -> CompoundOperationWrapper?> = { hash in + let statusKeyParams: () throws -> [BytesCodable] = { + [BytesCodable(wrappedValue: hash)] + } + + let statusFetchWrapper: CompoundOperationWrapper<[StorageResponse]> = + requestFactory.queryItems( + engine: connection, + keyParams: statusKeyParams, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: Preimage.statusForStoragePath + ) + + let callKeyParams: () throws -> [Preimage.PreimageKey] = { + let status = try statusFetchWrapper.targetOperation.extractNoCancellableResultData().first?.value + + guard let length = status?.length else { + return [] + } + + return [Preimage.PreimageKey(hash: hash, length: length)] + } + + let callFetchWrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( + engine: connection, + keyParams: callKeyParams, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: Preimage.preimageForStoragePath + ) + + callFetchWrapper.addDependency(wrapper: statusFetchWrapper) + + let mappingOperation = ClosureOperation?> { + let callKeys = try callKeyParams() + + guard !callKeys.isEmpty else { + return nil + } + + let responses = try callFetchWrapper.targetOperation.extractNoCancellableResultData() + guard let response = responses.first?.value else { + return nil + } + + let codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + + let decoder = try codingFactory.createDecoder(from: response.wrappedValue) + + return try decoder.read( + of: GenericType.call.name, + with: codingFactory.createRuntimeJsonContext().toRawContext() + ) + } + + mappingOperation.addDependency(callFetchWrapper.targetOperation) + + let dependencies = statusFetchWrapper.allOperations + callFetchWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } + + let callDecodingService = OperationCombiningService?>( + operationManager: OperationManager(operationQueue: operationQueue) + ) { + switch referendum.state.proposal { + case let .legacy(hash): + let wrapper = callFetchClosure(hash) + return [wrapper] + case let .inline(value): + return [CompoundOperationWrapper.createWithResult(value)] + case let .lookup(lookup): + if lookup.len <= Self.maxFetchCallSize { + let wrapper = callFetchClosure(lookup.hash) + return [wrapper] + } else { + return [] + } + case .none, .unknown: + return [] + } + } + + let callDecodingOperation = callDecodingService.longrunOperation() + let mappingOperation = ClosureOperation?> { + try callDecodingOperation.extractNoCancellableResultData().first ?? nil + } + + mappingOperation.addDependency(callDecodingOperation) + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: [callDecodingOperation]) + } + + private func createSpendAmountExtractionWrapper( + dependingOn callOperation: BaseOperation?>, + codingFactoryOperation: BaseOperation, + connection: JSONRPCEngine, + requestFactory: StorageRequestFactoryProtocol + ) -> CompoundOperationWrapper { + let operationManager = OperationManager(operationQueue: operationQueue) + let fetchService = OperationCombiningService( + operationManager: operationManager + ) { + guard let call = try callOperation.extractNoCancellableResultData() else { + return [CompoundOperationWrapper.createWithResult(nil)] + } + + let codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + let context = codingFactory.createRuntimeJsonContext() + + let codingPath = CallCodingPath(moduleName: call.moduleName, callName: call.callName) + + if codingPath == Treasury.spendCallPath { + let spendCall = try call.args.map(to: Treasury.SpendCall.self, with: context.toRawContext()) + + let details = ReferendumActionLocal.AmountSpendDetails( + amount: spendCall.amount, + beneficiaryAccountId: spendCall.beneficiary + ) + + return [CompoundOperationWrapper.createWithResult(details)] + } + + if codingPath == Treasury.approveProposalCallPath { + let approveCall = try call.args.map(to: Treasury.ApproveProposal.self, with: context.toRawContext()) + + let keyClosure: () throws -> [StringScaleMapper] = { + [StringScaleMapper(value: approveCall.proposalId)] + } + + let wrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( + engine: connection, + keyParams: keyClosure, + factory: { codingFactory }, + storagePath: Treasury.proposalsStoragePath + ) + + let mapOperation = ClosureOperation { + let responses = try wrapper.targetOperation.extractNoCancellableResultData() + guard let proposal = responses.first?.value else { + return nil + } + + return ReferendumActionLocal.AmountSpendDetails( + amount: proposal.value, + beneficiaryAccountId: proposal.beneficiary + ) + } + + mapOperation.addDependency(wrapper.targetOperation) + + return [CompoundOperationWrapper(targetOperation: mapOperation, dependencies: wrapper.allOperations)] + } + + return [CompoundOperationWrapper.createWithResult(nil)] + } + + let fetchOperation = fetchService.longrunOperation() + + let mapOperation = ClosureOperation { + try fetchOperation.extractNoCancellableResultData().first ?? nil + } + + mapOperation.addDependency(fetchOperation) + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: [fetchOperation]) + } +} + +extension Gov2ActionOperationFactory: ReferendumActionOperationFactoryProtocol { + func fetchActionWrapper( + for referendum: ReferendumLocal, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let callFetchWrapper = createCallFetchWrapper( + dependingOn: codingFactoryOperation, + referendum: referendum, + requestFactory: requestFactory, + connection: connection + ) + + callFetchWrapper.addDependency(operations: [codingFactoryOperation]) + + let amountDetailsWrapper = createSpendAmountExtractionWrapper( + dependingOn: callFetchWrapper.targetOperation, + codingFactoryOperation: codingFactoryOperation, + connection: connection, + requestFactory: requestFactory + ) + + amountDetailsWrapper.addDependency(wrapper: callFetchWrapper) + amountDetailsWrapper.addDependency(operations: [codingFactoryOperation]) + + let mapOperation = ClosureOperation { + let call = try callFetchWrapper.targetOperation.extractNoCancellableResultData() + let amountDetails = try amountDetailsWrapper.targetOperation.extractNoCancellableResultData() + + return ReferendumActionLocal(amountSpendDetails: amountDetails, call: call) + } + + mapOperation.addDependency(callFetchWrapper.targetOperation) + mapOperation.addDependency(amountDetailsWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + callFetchWrapper.allOperations + + amountDetailsWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index 6e83c8b727..493485d15a 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -32,6 +32,7 @@ final class Gov2LocalMappingFactory { let model = ReferendumStateLocal.Deciding( track: localTrack, + proposal: status.proposal, voting: .supportAndVotes(model: votes), since: deciding.since, period: track.decisionPeriod, @@ -59,6 +60,7 @@ final class Gov2LocalMappingFactory { let preparing = ReferendumStateLocal.Preparing( track: localTrack, + proposal: status.proposal, voting: .supportAndVotes(model: votes), deposit: status.decisionDeposit?.amount, since: status.submitted, diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift index 4969d8d0bc..1c8a0df24e 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -20,3 +20,11 @@ protocol ReferendumsOperationFactoryProtocol { runtimeProvider: RuntimeProviderProtocol ) -> CompoundOperationWrapper<[ReferendumVoterLocal]> } + +protocol ReferendumActionOperationFactoryProtocol { + func fetchActionWrapper( + for referendum: ReferendumLocal, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift new file mode 100644 index 0000000000..a06e841fb9 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -0,0 +1,7 @@ +import UIKit + +final class ReferendumDetailsInteractor { + weak var presenter: ReferendumDetailsInteractorOutputProtocol! +} + +extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift new file mode 100644 index 0000000000..218561c55e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -0,0 +1,21 @@ +import Foundation + +final class ReferendumDetailsPresenter { + weak var view: ReferendumDetailsViewProtocol? + let wireframe: ReferendumDetailsWireframeProtocol + let interactor: ReferendumDetailsInteractorInputProtocol + + init( + interactor: ReferendumDetailsInteractorInputProtocol, + wireframe: ReferendumDetailsWireframeProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + } +} + +extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { + func setup() {} +} + +extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift new file mode 100644 index 0000000000..e4ad87019f --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -0,0 +1,11 @@ +protocol ReferendumDetailsViewProtocol: AnyObject {} + +protocol ReferendumDetailsPresenterProtocol: AnyObject { + func setup() +} + +protocol ReferendumDetailsInteractorInputProtocol: AnyObject {} + +protocol ReferendumDetailsInteractorOutputProtocol: AnyObject {} + +protocol ReferendumDetailsWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift new file mode 100644 index 0000000000..4d446f00d5 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -0,0 +1,29 @@ +import UIKit + +final class ReferendumDetailsViewController: UIViewController { + typealias RootViewType = ReferendumDetailsViewLayout + + let presenter: ReferendumDetailsPresenterProtocol + + init(presenter: ReferendumDetailsPresenterProtocol) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = ReferendumDetailsViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + presenter.setup() + } +} + +extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift new file mode 100644 index 0000000000..533cf7594d --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -0,0 +1,42 @@ +import Foundation + +struct ReferendumDetailsViewFactory { + static func createView( + for referendum: ReferendumLocal, + state: GovernanceSharedState + ) -> ReferendumDetailsViewProtocol? { + guard let interactor = createInteractor(for: referendum, state: state) else { + return nil + } + + let wireframe = ReferendumDetailsWireframe() + + let presenter = ReferendumDetailsPresenter(interactor: interactor, wireframe: wireframe) + + let view = ReferendumDetailsViewController(presenter: presenter) + + presenter.view = view + interactor.presenter = presenter + + return view + } + + private static func createInteractor( + for _: ReferendumLocal, + state: GovernanceSharedState + ) -> ReferendumDetailsInteractor? { + guard let chain = state.settings.value else { + return nil + } + + let chainRegistry = ChainRegistryFacade.sharedRegistry + + guard + let connection = chainRegistry.getConnection(for: chain.chainId), + let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + return nil + } + + return ReferendumDetailsInteractor() + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift new file mode 100644 index 0000000000..7f5675b08e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -0,0 +1,12 @@ +import UIKit + +final class ReferendumDetailsViewLayout: UIView { + override init(frame: CGRect) { + super.init(frame: frame) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift new file mode 100644 index 0000000000..bb3b48abd9 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol {} diff --git a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift index f6a3c50b93..476170bfbd 100644 --- a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift +++ b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift @@ -4,34 +4,61 @@ import SubstrateSdk import RobinHood class Gov2OperationFactoryTests: XCTestCase { - func testLocalReferendumsFetch() { - // given + let chainId = "a2ee5a1f55a23dccd0c35e36512f9009e6e50a5654e8e5e469445d0748632aa8" + + var chainRegistry: ChainRegistryProtocol! + var connection: JSONRPCEngine! + var runtimeProvider: RuntimeProviderProtocol! + var operationQueue: OperationQueue! + var requestFactory: StorageRequestFactoryProtocol! + + override func setUpWithError() throws { + try super.setUpWithError() let storageFacade = SubstrateStorageTestFacade() - let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) - let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" + + chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) + + guard let connection = chainRegistry.getConnection(for: chainId) else { + throw ChainRegistryError.connectionUnavailable + } + + self.connection = connection + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + throw ChainRegistryError.runtimeMetadaUnavailable + } + + self.runtimeProvider = runtimeProvider + let operationQueue = OperationQueue() + self.operationQueue = operationQueue - let requestFactory = StorageRequestFactory( + self.requestFactory = StorageRequestFactory( remoteFactory: StorageKeyFactory(), operationManager: OperationManager(operationQueue: operationQueue) ) + } - guard let connection = chainRegistry.getConnection(for: chainId) else { - XCTFail("Can't get connection for chain id \(chainId)") - return + func testLocalReferendumsFetch() { + do { + let referendums = try fetchAllReferendums(for: chainRegistry) + Logger.shared.info("Referendums: \(referendums)") + } catch { + XCTFail("Unexpected error: \(error)") } + } - guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { - XCTFail("Can't get runtime provider for chain id \(chainId)") - return - } + func testFetchLocalVotes() throws { + // given + let accountId = try "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY".toAccountId() // when let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) - let wrapper = operationFactory.fetchAllReferendumsWrapper( + let wrapper = operationFactory.fetchAccountVotesWrapper( + for: accountId, from: connection, runtimeProvider: runtimeProvider ) @@ -41,43 +68,24 @@ class Gov2OperationFactoryTests: XCTestCase { // then do { - let referendums = try wrapper.targetOperation.extractNoCancellableResultData() - Logger.shared.info("Referendums: \(referendums)") + let votes = try wrapper.targetOperation.extractNoCancellableResultData() + Logger.shared.info("Votes: \(votes)") } catch { XCTFail("Unexpected error: \(error)") } } - func testFetchLocalVotes() throws { + func testVotersFetch() throws { // given - let storageFacade = SubstrateStorageTestFacade() - let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) - let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" - let accountId = try "5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc".toAccountId() - let operationQueue = OperationQueue() - - let requestFactory = StorageRequestFactory( - remoteFactory: StorageKeyFactory(), - operationManager: OperationManager(operationQueue: operationQueue) - ) - - guard let connection = chainRegistry.getConnection(for: chainId) else { - XCTFail("Can't get connection for chain id \(chainId)") - return - } - - guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { - XCTFail("Can't get runtime provider for chain id \(chainId)") - return - } + let referendumIndex: Referenda.ReferendumIndex = 0 // when let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) - let wrapper = operationFactory.fetchAccountVotesWrapper( - for: accountId, + let wrapper = operationFactory.fetchVotersWrapper( + for: referendumIndex, from: connection, runtimeProvider: runtimeProvider ) @@ -88,19 +96,44 @@ class Gov2OperationFactoryTests: XCTestCase { do { let votes = try wrapper.targetOperation.extractNoCancellableResultData() - Logger.shared.info("Votes: \(votes)") + Logger.shared.info("Voters: \(votes)") } catch { XCTFail("Unexpected error: \(error)") } } - func testVotersFetch() throws { - // given + func testActionDetails() { + do { + let referendums = try fetchAllReferendums(for: chainRegistry) - let storageFacade = SubstrateStorageTestFacade() - let chainRegistry = ChainRegistryFacade.setupForIntegrationTest(with: storageFacade) - let chainId = "ea5af80801ea4579cedd029eaaa74938f0ea8dcaf507c8af96f2813d27d071ca" - let referendumIndex: Referenda.ReferendumIndex = 0 + let operationFactory = Gov2ActionOperationFactory( + requestFactory: requestFactory, + operationQueue: operationQueue + ) + + let wrappers = referendums.map { referendum in + operationFactory.fetchActionWrapper( + for: referendum, + connection: connection, + runtimeProvider: runtimeProvider + ) + } + + let operations = wrappers.flatMap { $0.allOperations } + + operationQueue.addOperations(operations, waitUntilFinished: true) + + let details = try wrappers.map { try $0.targetOperation.extractNoCancellableResultData() } + + Logger.shared.info("Did receive details: \(details)") + } catch { + XCTFail("Unexpected error: \(error)") + } + } + + // MARK: Private + + private func fetchAllReferendums(for chainRegistry: ChainRegistryProtocol) throws -> [ReferendumLocal] { let operationQueue = OperationQueue() let requestFactory = StorageRequestFactory( @@ -109,34 +142,22 @@ class Gov2OperationFactoryTests: XCTestCase { ) guard let connection = chainRegistry.getConnection(for: chainId) else { - XCTFail("Can't get connection for chain id \(chainId)") - return + throw ChainRegistryError.connectionUnavailable } guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { - XCTFail("Can't get runtime provider for chain id \(chainId)") - return + throw ChainRegistryError.runtimeMetadaUnavailable } - // when - let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) - let wrapper = operationFactory.fetchVotersWrapper( - for: referendumIndex, + let wrapper = operationFactory.fetchAllReferendumsWrapper( from: connection, runtimeProvider: runtimeProvider ) operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: true) - // then - - do { - let votes = try wrapper.targetOperation.extractNoCancellableResultData() - Logger.shared.info("Voters: \(votes)") - } catch { - XCTFail("Unexpected error: \(error)") - } + return try wrapper.targetOperation.extractNoCancellableResultData() } } From fb76ec374429045d18f2b7d2715f30faebcfeee3 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 11 Oct 2022 15:12:03 +0500 Subject: [PATCH 027/229] fix interactor --- .../ReferendumDetailsInteractor.swift | 26 ++++++++++++++++- .../ReferendumDetailsViewFactory.swift | 29 +++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index a06e841fb9..d18e634308 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -1,7 +1,31 @@ import UIKit +import SubstrateSdk final class ReferendumDetailsInteractor { - weak var presenter: ReferendumDetailsInteractorOutputProtocol! + weak var presenter: ReferendumDetailsInteractorOutputProtocol? + + let referendum: ReferendumLocal + let chain: ChainModel + let actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol + let connection: JSONRPCEngine + let runtimeProvider: RuntimeProviderProtocol + let identityOperationFactory: IdentityOperationFactoryProtocol + + init( + referendum: ReferendumLocal, + chain: ChainModel, + actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + identityOperationFactory: IdentityOperationFactoryProtocol + ) { + self.referendum = referendum + self.chain = chain + self.actionDetailsOperationFactory = actionDetailsOperationFactory + self.connection = connection + self.runtimeProvider = runtimeProvider + self.identityOperationFactory = identityOperationFactory + } } extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 533cf7594d..1bd8d62160 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -1,4 +1,6 @@ import Foundation +import SubstrateSdk +import RobinHood struct ReferendumDetailsViewFactory { static func createView( @@ -22,7 +24,7 @@ struct ReferendumDetailsViewFactory { } private static func createInteractor( - for _: ReferendumLocal, + for referendum: ReferendumLocal, state: GovernanceSharedState ) -> ReferendumDetailsInteractor? { guard let chain = state.settings.value else { @@ -37,6 +39,29 @@ struct ReferendumDetailsViewFactory { return nil } - return ReferendumDetailsInteractor() + let operationQueue = OperationManagerFacade.sharedDefaultQueue + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + let actionDetailsOperationFactory = Gov2ActionOperationFactory( + requestFactory: requestFactory, + operationQueue: operationQueue + ) + + let identityOperationFactory = IdentityOperationFactory( + requestFactory: requestFactory, + emptyIdentitiesWhenNoStorage: true + ) + + return ReferendumDetailsInteractor( + referendum: referendum, + chain: chain, + actionDetailsOperationFactory: actionDetailsOperationFactory, + connection: connection, + runtimeProvider: runtimeProvider, + identityOperationFactory: identityOperationFactory + ) } } From a9bd8901b5bd728ca46052427b44d4404bd466e6 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 11 Oct 2022 16:11:40 +0500 Subject: [PATCH 028/229] add error --- novawallet.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 0146a3f32d..0d72aaf525 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -8081,6 +8081,13 @@ path = StakingDuration; sourceTree = ""; }; + 8469D5A328F5817C0074FEE3 /* Model */ = { + isa = PBXGroup; + children = ( + ); + path = Model; + sourceTree = ""; + }; 846A682A274693D400D1A47A /* Crowdloan */ = { isa = PBXGroup; children = ( @@ -12537,6 +12544,7 @@ B4F0332763AFF64A3793C679 /* ReferendumDetails */ = { isa = PBXGroup; children = ( + 8469D5A328F5817C0074FEE3 /* Model */, C3ABAD23C0039AFA8351C650 /* ReferendumDetailsProtocols.swift */, 5E2EB9EE4A87BD4A74040784 /* ReferendumDetailsWireframe.swift */, 78536852751EF56F58C5691E /* ReferendumDetailsPresenter.swift */, From 69146043469553f8cffe87c3d4572c04b5e68a33 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 12 Oct 2022 11:15:54 +0500 Subject: [PATCH 029/229] referendum details update --- novawallet.xcodeproj/project.pbxproj | 4 + .../Model/GovernanceSharedState.swift | 14 +++ .../ReferendumDetailsInteractorError.swift | 11 +++ .../ReferendumDetailsInteractor.swift | 95 ++++++++++++++++++- .../ReferendumDetailsProtocols.swift | 15 ++- .../ReferendumDetailsViewFactory.swift | 20 +++- .../Referendums/ReferendumsInteractor.swift | 7 +- .../Parent/VoteChildPresenterFactory.swift | 8 -- 8 files changed, 156 insertions(+), 18 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 0d72aaf525..aa6aea0167 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1021,6 +1021,7 @@ 846952A42852A1640083E0B4 /* StakingDuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846952A32852A1640083E0B4 /* StakingDuration.swift */; }; 846952A62852A1E60083E0B4 /* AuraStakingDurationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846952A52852A1E60083E0B4 /* AuraStakingDurationFactory.swift */; }; 8469936B26CD1BBE002CC786 /* RuntimePoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8469936A26CD1BBE002CC786 /* RuntimePoolTests.swift */; }; + 8469D5A828F683930074FEE3 /* ReferendumDetailsInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8469D5A728F683930074FEE3 /* ReferendumDetailsInteractorError.swift */; }; 846A2601267C768500429A7F /* CrowdloanContributionMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A2600267C768500429A7F /* CrowdloanContributionMapper.swift */; }; 846A2606267C792000429A7F /* CrowdloanContributionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A2605267C792000429A7F /* CrowdloanContributionResponse.swift */; }; 846A2C4325271CDE00731018 /* TransactionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A2C4225271CDE00731018 /* TransactionType.swift */; }; @@ -3832,6 +3833,7 @@ 846952A32852A1640083E0B4 /* StakingDuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingDuration.swift; sourceTree = ""; }; 846952A52852A1E60083E0B4 /* AuraStakingDurationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuraStakingDurationFactory.swift; sourceTree = ""; }; 8469936A26CD1BBE002CC786 /* RuntimePoolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimePoolTests.swift; sourceTree = ""; }; + 8469D5A728F683930074FEE3 /* ReferendumDetailsInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsInteractorError.swift; sourceTree = ""; }; 846A2600267C768500429A7F /* CrowdloanContributionMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionMapper.swift; sourceTree = ""; }; 846A2605267C792000429A7F /* CrowdloanContributionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionResponse.swift; sourceTree = ""; }; 846A2C4225271CDE00731018 /* TransactionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionType.swift; sourceTree = ""; }; @@ -8084,6 +8086,7 @@ 8469D5A328F5817C0074FEE3 /* Model */ = { isa = PBXGroup; children = ( + 8469D5A728F683930074FEE3 /* ReferendumDetailsInteractorError.swift */, ); path = Model; sourceTree = ""; @@ -13976,6 +13979,7 @@ 849DEBD425ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift in Sources */, 84CD82B8263C3249001A6F01 /* SubstrateProviderSubscriber+Default.swift in Sources */, 84EE2FAD2891213E00A98816 /* WalletManageWireframe.swift in Sources */, + 8469D5A828F683930074FEE3 /* ReferendumDetailsInteractorError.swift in Sources */, 845BB8B825E4465F00E5FCDC /* ExtrinsicService.swift in Sources */, 8482F625280C45340006C3A0 /* DisplayWalletViewModel.swift in Sources */, F4F65C2E26D8B7F7002EE838 /* FWXAxisChartLegendView.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index 614b7fe4e3..8a442d903d 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -1,20 +1,34 @@ import Foundation import SoraKeystore +import RobinHood final class GovernanceSharedState { let settings: GovernanceChainSettings let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol + let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol private(set) var blockTimeService: BlockTimeEstimationServiceProtocol? init( chainRegistry: ChainRegistryProtocol = ChainRegistryFacade.sharedRegistry, substrateStorageFacade: StorageFacadeProtocol = SubstrateDataStorageFacade.shared, + generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol? = nil, blockTimeService: BlockTimeEstimationServiceProtocol? = nil, internalSettings: SettingsManagerProtocol = SettingsManager.shared ) { settings = GovernanceChainSettings(chainRegistry: chainRegistry, settings: internalSettings) govMetadataLocalSubscriptionFactory = GovMetadataLocalSubscriptionFactory(storageFacade: substrateStorageFacade) self.blockTimeService = blockTimeService + + if let generalLocalSubscriptionFactory = generalLocalSubscriptionFactory { + self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory + } else { + self.generalLocalSubscriptionFactory = GeneralStorageSubscriptionFactory( + chainRegistry: chainRegistry, + storageFacade: substrateStorageFacade, + operationManager: OperationManager(operationQueue: OperationManagerFacade.sharedDefaultQueue), + logger: Logger.shared + ) + } } func replaceBlockTimeService(_ newService: BlockTimeEstimationServiceProtocol?) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift new file mode 100644 index 0000000000..4b45195ba2 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift @@ -0,0 +1,11 @@ +import Foundation + +enum ReferendumDetailsInteractorError: Error { + case referendumFailed(_ internalError: Error) + case actionDetailsFailed(_ internalError: Error) + case metadataFailed(_ internalError: Error) + case identitiesFailed(_ internalError: Error) + case priceFailed(_ internalError: Error) + case blockNumberFailed(_ internalError: Error) + case blockTimeFailed(_ internalError: Error) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index d18e634308..512e235228 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -1,5 +1,6 @@ import UIKit import SubstrateSdk +import RobinHood final class ReferendumDetailsInteractor { weak var presenter: ReferendumDetailsInteractorOutputProtocol? @@ -10,6 +11,14 @@ final class ReferendumDetailsInteractor { let connection: JSONRPCEngine let runtimeProvider: RuntimeProviderProtocol let identityOperationFactory: IdentityOperationFactoryProtocol + let blockTimeService: BlockTimeEstimationServiceProtocol + let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol + let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol + let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol + let operationQueue: OperationQueue + + private var priceProvider: AnySingleValueProvider? + private var blockNumberSubscription: AnyDataProvider? init( referendum: ReferendumLocal, @@ -17,7 +26,13 @@ final class ReferendumDetailsInteractor { actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, - identityOperationFactory: IdentityOperationFactoryProtocol + blockTimeService: BlockTimeEstimationServiceProtocol, + identityOperationFactory: IdentityOperationFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, + govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol, + currencyManager: CurrencyManagerProtocol, + operationQueue: OperationQueue ) { self.referendum = referendum self.chain = chain @@ -25,7 +40,83 @@ final class ReferendumDetailsInteractor { self.connection = connection self.runtimeProvider = runtimeProvider self.identityOperationFactory = identityOperationFactory + self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory + self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory + self.blockTimeService = blockTimeService + self.govMetadataLocalSubscriptionFactory = govMetadataLocalSubscriptionFactory + self.operationQueue = operationQueue + self.currencyManager = currencyManager + } + + private func handleReferendumSubscription(result: Result) { + + } + + private func subscribeReferendum() { + let referendumIndex = referendum.index + + let request = MapSubscriptionRequest( + storagePath: Referenda.referendumInfo, + localKey: "" + ) { + StringScaleMapper(value: referendumIndex) + } + + let subscription = CallbackStorageSubscription( + request: request, + connection: connection, + runtimeService: runtimeProvider, + repository: nil, + operationQueue: operationQueue, + callbackQueue: .main + ) { [weak self] result in + + } + } + + private func makeSubscriptions() { + if let priceId = chain.utilityAsset()?.priceId { + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } + + blockNumberSubscription = subscribeToBlockNumber(for: chain.chainId) } } -extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol {} +extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol { + func setup() { + makeSubscriptions() + } +} + +extension ReferendumDetailsInteractor: GeneralLocalStorageSubscriber, GeneralLocalStorageHandler { + func handleBlockNumber(result: Result, chainId: ChainModel.Id) { + switch result { + case let .success(blockNumber): + if let blockNumber = blockNumber { + presenter?.didReceiveBlockNumber(blockNumber) + } + case let .failure(error): + presenter?.didReceiveError(.blockNumberFailed(error)) + } + } +} + +extension ReferendumDetailsInteractor: PriceLocalSubscriptionHandler, PriceLocalStorageSubscriber { + func handlePrice(result: Result, priceId _: AssetModel.PriceId) { + switch result { + case let .success(price): + presenter?.didReceivePrice(price) + case let .failure(error): + presenter?.didReceiveError(.priceFailed(error)) + } + } +} + +extension ReferendumDetailsInteractor: SelectedCurrencyDepending { + func applyCurrency() { + if presenter != nil { + subscribeToAssetPrice() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index e4ad87019f..41a99722b2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -4,8 +4,19 @@ protocol ReferendumDetailsPresenterProtocol: AnyObject { func setup() } -protocol ReferendumDetailsInteractorInputProtocol: AnyObject {} +protocol ReferendumDetailsInteractorInputProtocol: AnyObject { + func setup() +} -protocol ReferendumDetailsInteractorOutputProtocol: AnyObject {} +protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { + func didReceiveReferendum(_ referendum: ReferendumLocal) + func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) + func didReceiveMetadata(_ referendumMetadata: ReferendumMetadataLocal?) + func didReceiveIdentities(_ identities: [AccountId: AccountIdentity]) + func didReceivePrice(_ price: PriceData?) + func didReceiveBlockNumber(_ blockNumber: BlockNumber) + func didReceiveBlockTime(_ blockTime: BlockTime) + func didReceiveError(_ error: ReferendumDetailsInteractorError) +} protocol ReferendumDetailsWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 1bd8d62160..edf9f25090 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -7,7 +7,13 @@ struct ReferendumDetailsViewFactory { for referendum: ReferendumLocal, state: GovernanceSharedState ) -> ReferendumDetailsViewProtocol? { - guard let interactor = createInteractor(for: referendum, state: state) else { + guard + let currencyManager = CurrencyManager.shared, + let interactor = createInteractor( + for: referendum, + currencyManager: currencyManager, + state: state + ) else { return nil } @@ -25,6 +31,7 @@ struct ReferendumDetailsViewFactory { private static func createInteractor( for referendum: ReferendumLocal, + currencyManager: CurrencyManagerProtocol, state: GovernanceSharedState ) -> ReferendumDetailsInteractor? { guard let chain = state.settings.value else { @@ -35,7 +42,8 @@ struct ReferendumDetailsViewFactory { guard let connection = chainRegistry.getConnection(for: chain.chainId), - let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId), + let blockTimeService = state.blockTimeService else { return nil } @@ -61,7 +69,13 @@ struct ReferendumDetailsViewFactory { actionDetailsOperationFactory: actionDetailsOperationFactory, connection: connection, runtimeProvider: runtimeProvider, - identityOperationFactory: identityOperationFactory + blockTimeService: blockTimeService, + identityOperationFactory: identityOperationFactory, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, + govMetadataLocalSubscriptionFactory: state.govMetadataLocalSubscriptionFactory, + currencyManager: currencyManager, + operationQueue: OperationManagerFacade.sharedDefaultQueue ) } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 33daca51f2..7390dc0deb 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -12,12 +12,15 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let referendumsOperationFactory: ReferendumsOperationFactoryProtocol - let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol let currencyManager: CurrencyManagerProtocol let applicationHandler: ApplicationHandlerProtocol let serviceFactory: GovernanceServiceFactoryProtocol let operationQueue: OperationQueue + var generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol { + governanceState.generalLocalSubscriptionFactory + } + var govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { governanceState.govMetadataLocalSubscriptionFactory } @@ -40,7 +43,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, referendumsOperationFactory: ReferendumsOperationFactoryProtocol, - generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, serviceFactory: GovernanceServiceFactoryProtocol, applicationHandler: ApplicationHandlerProtocol, operationQueue: OperationQueue, @@ -52,7 +54,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory self.referendumsOperationFactory = referendumsOperationFactory - self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory self.serviceFactory = serviceFactory self.operationQueue = operationQueue self.applicationHandler = applicationHandler diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index f303ef56a9..ac1eb9d9f1 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -117,13 +117,6 @@ final class VoteChildPresenterFactory { logger: logger ) - let generalLocalSubscriptionFactory = GeneralStorageSubscriptionFactory( - chainRegistry: chainRegistry, - storageFacade: substrateStorageFacade, - operationManager: OperationManager(operationQueue: operationQueue), - logger: logger - ) - return ReferendumsInteractor( selectedMetaAccount: wallet, governanceState: state, @@ -131,7 +124,6 @@ final class VoteChildPresenterFactory { walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, priceLocalSubscriptionFactory: priceProviderFactory, referendumsOperationFactory: referendumOperationFactory, - generalLocalSubscriptionFactory: generalLocalSubscriptionFactory, serviceFactory: serviceFactory, applicationHandler: applicationHandler, operationQueue: operationQueue, From c743c2e38dbaad7c863e181b1a09f3aecc997349 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 12 Oct 2022 16:23:22 +0500 Subject: [PATCH 030/229] fix gov2 referendum fetch --- .../Types/Referenda/ReferendumInfo.swift | 4 ++ .../Operation/Gov2OperationFactory.swift | 47 +++++++++++++++++++ .../GovernanceOperationProtocols.swift | 7 +++ 3 files changed, 58 insertions(+) diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift index edafe57090..04fe05ae42 100644 --- a/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendumInfo.swift @@ -71,6 +71,10 @@ enum ReferendumInfo: Decodable { struct ReferendumIndexKey: JSONListConvertible, Hashable { let referendumIndex: Referenda.ReferendumIndex + init(referendumIndex: Referenda.ReferendumIndex) { + self.referendumIndex = referendumIndex + } + init(jsonList: [JSON], context: [CodingUserInfoKey: Any]?) throws { let expectedFieldsCount = 1 let actualFieldsCount = jsonList.count diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 8d502544cc..e3d2c8128f 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -213,6 +213,53 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } + func fetchReferendumWrapper( + for remoteReferendum: ReferendumInfo, + index: Referenda.ReferendumIndex, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper { + let additionalInfoWrapper = createAdditionalInfoWrapper(from: connection, runtimeProvider: runtimeProvider) + + let referendumOperation = ClosureOperation<[ReferendumIndexKey: ReferendumInfo]> { + let referendumIndexKey = ReferendumIndexKey(referendumIndex: index) + return [referendumIndexKey: remoteReferendum] + } + + let enactmentsWrapper = createEnacmentTimeFetchWrapper( + dependingOn: referendumOperation, + connection: connection, + runtimeProvider: runtimeProvider + ) + + enactmentsWrapper.addDependency(operations: [referendumOperation]) + + let mergeOperation = createReferendumMapOperation( + dependingOn: referendumOperation, + additionalInfoOperation: additionalInfoWrapper.targetOperation, + enactmentsOperation: enactmentsWrapper.targetOperation + ) + + mergeOperation.addDependency(referendumOperation) + mergeOperation.addDependency(additionalInfoWrapper.targetOperation) + mergeOperation.addDependency(enactmentsWrapper.targetOperation) + + let mapOperation = ClosureOperation { + guard let referendum = try mergeOperation.extractNoCancellableResultData().first else { + throw BaseOperationError.unexpectedDependentResult + } + + return referendum + } + + mapOperation.addDependency(mergeOperation) + + let dependencies = [referendumOperation] + additionalInfoWrapper.allOperations + + enactmentsWrapper.allOperations + [mergeOperation] + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } + func fetchAccountVotesWrapper( for accountId: AccountId, from connection: JSONRPCEngine, diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift index 1c8a0df24e..6095f0c48f 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -8,6 +8,13 @@ protocol ReferendumsOperationFactoryProtocol { runtimeProvider: RuntimeProviderProtocol ) -> CompoundOperationWrapper<[ReferendumLocal]> + func fetchReferendumWrapper( + for remoteReferendum: ReferendumInfo, + index: Referenda.ReferendumIndex, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper + func fetchAccountVotesWrapper( for accountId: AccountId, from connection: JSONRPCEngine, From ee7cb52e0233095112519b25354ac6bab27461e1 Mon Sep 17 00:00:00 2001 From: Gulnaz <666lynx666@mail.ru> Date: Wed, 12 Oct 2022 17:15:14 +0400 Subject: [PATCH 031/229] UI for list of referendums (#435) * added control and top view * added cell * fix layout * layout fixes * added factory * handle all states in view model factory * improvements for factory * added your votes * buildfix * added time updates * buildfixes * change models * added status color * added timer * fixes --- novawallet.xcodeproj/project.pbxproj | 72 ++- .../colorDarkGreen.colorset/Contents.json | 20 + .../colorDarkYellow.colorset/Contents.json | 20 + .../colorGreen24.colorset/Contents.json | 6 +- .../colorRed40.colorset/Contents.json | 6 +- .../colorRedFF3A69.colorset/Contents.json | 20 + .../iconFire.imageset/Contents.json | 12 + .../iconFire.imageset/Fire.pdf | Bin 0 -> 2642 bytes .../Extension/Foundation/DateFormatter.swift | 15 + .../TimeInterval+Localization.swift | 14 + .../Common/ViewModel/TitleIconViewModel.swift | 2 +- .../CrowdloanListViewManager.swift | 8 +- .../Model/ReferendumsModelFactory.swift | 570 ++++++++++++++++++ .../Model/ReferendumsViewModel.swift | 13 + .../Governance/Model/StatusTimeModel.swift | 7 + .../Referendums/ReferendumsPresenter.swift | 131 +++- .../Referendums/ReferendumsProtocols.swift | 2 + .../Referendums/ReferendumsViewManager.swift | 72 ++- .../Governance/View/ReferendumInfoView.swift | 172 ++++++ .../View/ReferendumTableViewCell.swift | 72 +++ .../View/Slider/GovernanceStyle.swift | 33 + .../View/Slider/SegmentedSliderView.swift | 129 ++++ .../Governance/View/Slider/SliderLayer.swift | 90 +++ .../Governance/View/Slider/ThumbLayer.swift | 54 ++ .../Vote/Governance/View/UILabel+Style.swift | 54 ++ .../Governance/View/VotingProgressView.swift | 88 +++ .../Vote/Governance/View/YourVoteView.swift | 118 ++++ .../View/VoteStatusSectionView.swift} | 8 +- .../Parent/VoteChildPresenterFactory.swift | 9 + novawallet/en.lproj/Localizable.strings | 22 + novawallet/ru.lproj/Localizable.strings | 22 + 31 files changed, 1830 insertions(+), 31 deletions(-) create mode 100644 novawallet/Assets.xcassets/colorDarkGreen.colorset/Contents.json create mode 100644 novawallet/Assets.xcassets/colorDarkYellow.colorset/Contents.json create mode 100644 novawallet/Assets.xcassets/colorRedFF3A69.colorset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconFire.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconFire.imageset/Fire.pdf create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumsModelFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumsViewModel.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/StatusTimeModel.swift create mode 100644 novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift create mode 100644 novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift create mode 100644 novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift create mode 100644 novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift create mode 100644 novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift create mode 100644 novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift create mode 100644 novawallet/Modules/Vote/Governance/View/UILabel+Style.swift create mode 100644 novawallet/Modules/Vote/Governance/View/VotingProgressView.swift create mode 100644 novawallet/Modules/Vote/Governance/View/YourVoteView.swift rename novawallet/Modules/Vote/{Crowdloan/CrowdloanList/View/CrowdloanStatusSectionView.swift => Parent/View/VoteStatusSectionView.swift} (94%) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 0146a3f32d..c845fea219 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1432,7 +1432,7 @@ 84981CC32666D95F00C4C691 /* GradientButton+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84981CC22666D95F00C4C691 /* GradientButton+Style.swift */; }; 849842E626587573006BBB9F /* MultilineTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849842E526587573006BBB9F /* MultilineTableViewCell.swift */; }; 849842FE26592C2B006BBB9F /* StatusSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849842FD26592C2B006BBB9F /* StatusSectionView.swift */; }; - 8498430326592D29006BBB9F /* CrowdloanStatusSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8498430226592D29006BBB9F /* CrowdloanStatusSectionView.swift */; }; + 8498430326592D29006BBB9F /* VoteStatusSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8498430226592D29006BBB9F /* VoteStatusSectionView.swift */; }; 8498430926592E5D006BBB9F /* CrowdloansViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8498430826592E5D006BBB9F /* CrowdloansViewModel.swift */; }; 849976B327B2430300B14A6C /* DAppMetamaskTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849976B227B2430300B14A6C /* DAppMetamaskTransport.swift */; }; 849976B827B24BCB00B14A6C /* DAppPolkadotExtensionTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849976B727B24BCB00B14A6C /* DAppPolkadotExtensionTransport.swift */; }; @@ -2157,6 +2157,12 @@ 85A093F6055DDD2E2E9253F2 /* ControllerAccountProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F829E7F8B39EE7D977001510 /* ControllerAccountProtocols.swift */; }; 86EB789787B731691B36C827 /* OnChainTransferSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1A2F7E5E278FDCC89FE097 /* OnChainTransferSetupPresenter.swift */; }; 87F7556E02F6F5BB6F1B1AEA /* ParitySignerTxQrViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A5DCA28ABF42D342BBDF9A /* ParitySignerTxQrViewLayout.swift */; }; + 880059D828EEBC0200E87B9B /* SliderLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059D728EEBC0200E87B9B /* SliderLayer.swift */; }; + 880059DA28EF092800E87B9B /* ThumbLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059D928EF092800E87B9B /* ThumbLayer.swift */; }; + 880059DC28EF092F00E87B9B /* SegmentedSliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059DB28EF092F00E87B9B /* SegmentedSliderView.swift */; }; + 880059DF28EF09E100E87B9B /* GovernanceStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059DE28EF09E100E87B9B /* GovernanceStyle.swift */; }; + 880059E128EF0A5C00E87B9B /* VotingProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059E028EF0A5C00E87B9B /* VotingProgressView.swift */; }; + 880059E328EF128000E87B9B /* ReferendumInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059E228EF128000E87B9B /* ReferendumInfoView.swift */; }; 880855ED28D062A9004255E7 /* Array+AddOrReplace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855EC28D062A9004255E7 /* Array+AddOrReplace.swift */; }; 880855F028D099F2004255E7 /* CrowdloanOnChainSyncService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855EF28D099F2004255E7 /* CrowdloanOnChainSyncService.swift */; }; 880855F228D09A0B004255E7 /* CrowdloanContributionData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855F128D09A0B004255E7 /* CrowdloanContributionData.swift */; }; @@ -2211,6 +2217,10 @@ 8887814028B7AAB700E7290F /* RoundedIconTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8887813F28B7AAB700E7290F /* RoundedIconTitleView.swift */; }; 888B853828ED966600AC9614 /* SkeletonableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 888B853728ED966600AC9614 /* SkeletonableView.swift */; }; 8890E51628DDC98C001D3994 /* SubstrateStorageMigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8890E51528DDC98C001D3994 /* SubstrateStorageMigrationTests.swift */; }; + 8892284828F353A5003F8B9E /* ReferendumsModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8892284728F353A5003F8B9E /* ReferendumsModelFactory.swift */; }; + 8892284A28F35410003F8B9E /* ReferendumsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8892284928F35410003F8B9E /* ReferendumsViewModel.swift */; }; + 889D889528F01E5B00C4320F /* ReferendumTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 889D889428F01E5B00C4320F /* ReferendumTableViewCell.swift */; }; + 889D889728F022AA00C4320F /* UILabel+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 889D889628F022AA00C4320F /* UILabel+Style.swift */; }; 88A0C52128D49A090083A524 /* CrowdloanOffChainSyncService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A0C52028D49A090083A524 /* CrowdloanOffChainSyncService.swift */; }; 88A0E0FF28A284C700A9C940 /* SelectedCurrencyDepending.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A0E0FC28A284C700A9C940 /* SelectedCurrencyDepending.swift */; }; 88A0E10028A284C700A9C940 /* CurrencyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A0E0FD28A284C700A9C940 /* CurrencyManager.swift */; }; @@ -2225,6 +2235,8 @@ 88AC186328CA3F0000892A9B /* GenericCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AC186228CA3F0000892A9B /* GenericCollectionViewLayout.swift */; }; 88AC186528CA461F00892A9B /* ModalSheetCollectionViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AC186428CA461F00892A9B /* ModalSheetCollectionViewProtocol.swift */; }; 88AF35DE28C21D28003730DA /* LocksSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AF35DD28C21D28003730DA /* LocksSubscription.swift */; }; + 88B1862A28EF30A600D49854 /* YourVoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B1862928EF30A600D49854 /* YourVoteView.swift */; }; + 88B438E728F6C629001FC08A /* StatusTimeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B438E628F6C629001FC08A /* StatusTimeModel.swift */; }; 88BB21A028D34C660019C6B4 /* DataProviderChange+Identifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88BB219F28D34C660019C6B4 /* DataProviderChange+Identifier.swift */; }; 88C017E628C60A65003B2D28 /* AssetLockMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C017E528C60A65003B2D28 /* AssetLockMapper.swift */; }; 88C7165428C894510015D1E9 /* CollectionViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C7165328C894510015D1E9 /* CollectionViewDelegate.swift */; }; @@ -4249,7 +4261,7 @@ 84981CC22666D95F00C4C691 /* GradientButton+Style.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GradientButton+Style.swift"; sourceTree = ""; }; 849842E526587573006BBB9F /* MultilineTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineTableViewCell.swift; sourceTree = ""; }; 849842FD26592C2B006BBB9F /* StatusSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusSectionView.swift; sourceTree = ""; }; - 8498430226592D29006BBB9F /* CrowdloanStatusSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanStatusSectionView.swift; sourceTree = ""; }; + 8498430226592D29006BBB9F /* VoteStatusSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteStatusSectionView.swift; sourceTree = ""; }; 8498430826592E5D006BBB9F /* CrowdloansViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloansViewModel.swift; sourceTree = ""; }; 849976B227B2430300B14A6C /* DAppMetamaskTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppMetamaskTransport.swift; sourceTree = ""; }; 849976B727B24BCB00B14A6C /* DAppPolkadotExtensionTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppPolkadotExtensionTransport.swift; sourceTree = ""; }; @@ -4980,6 +4992,12 @@ 86F7A369E31DCB9ABD556EE9 /* CrowdloanListPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanListPresenter.swift; sourceTree = ""; }; 86F9063B2DF46E7B65B5248E /* Pods_novawalletAll_novawalletIntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_novawalletAll_novawalletIntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 87CD8C618D61C78EA8C58532 /* ParitySignerTxScanViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerTxScanViewLayout.swift; sourceTree = ""; }; + 880059D728EEBC0200E87B9B /* SliderLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderLayer.swift; sourceTree = ""; }; + 880059D928EF092800E87B9B /* ThumbLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbLayer.swift; sourceTree = ""; }; + 880059DB28EF092F00E87B9B /* SegmentedSliderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentedSliderView.swift; sourceTree = ""; }; + 880059DE28EF09E100E87B9B /* GovernanceStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceStyle.swift; sourceTree = ""; }; + 880059E028EF0A5C00E87B9B /* VotingProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VotingProgressView.swift; sourceTree = ""; }; + 880059E228EF128000E87B9B /* ReferendumInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumInfoView.swift; sourceTree = ""; }; 880855EC28D062A9004255E7 /* Array+AddOrReplace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+AddOrReplace.swift"; sourceTree = ""; }; 880855EF28D099F2004255E7 /* CrowdloanOnChainSyncService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanOnChainSyncService.swift; sourceTree = ""; }; 880855F128D09A0B004255E7 /* CrowdloanContributionData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionData.swift; sourceTree = ""; }; @@ -5034,7 +5052,11 @@ 8887813F28B7AAB700E7290F /* RoundedIconTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedIconTitleView.swift; sourceTree = ""; }; 888B853728ED966600AC9614 /* SkeletonableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkeletonableView.swift; sourceTree = ""; }; 8890E51528DDC98C001D3994 /* SubstrateStorageMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubstrateStorageMigrationTests.swift; sourceTree = ""; }; + 8892284728F353A5003F8B9E /* ReferendumsModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsModelFactory.swift; sourceTree = ""; }; + 8892284928F35410003F8B9E /* ReferendumsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsViewModel.swift; sourceTree = ""; }; 889A825F58F5CB54118A9D35 /* SelectValidatorsStartWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectValidatorsStartWireframe.swift; sourceTree = ""; }; + 889D889428F01E5B00C4320F /* ReferendumTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumTableViewCell.swift; sourceTree = ""; }; + 889D889628F022AA00C4320F /* UILabel+Style.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Style.swift"; sourceTree = ""; }; 88A0C52028D49A090083A524 /* CrowdloanOffChainSyncService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanOffChainSyncService.swift; sourceTree = ""; }; 88A0E0FC28A284C700A9C940 /* SelectedCurrencyDepending.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectedCurrencyDepending.swift; sourceTree = ""; }; 88A0E0FD28A284C700A9C940 /* CurrencyManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CurrencyManager.swift; sourceTree = ""; }; @@ -5049,6 +5071,8 @@ 88AC186228CA3F0000892A9B /* GenericCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericCollectionViewLayout.swift; sourceTree = ""; }; 88AC186428CA461F00892A9B /* ModalSheetCollectionViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalSheetCollectionViewProtocol.swift; sourceTree = ""; }; 88AF35DD28C21D28003730DA /* LocksSubscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksSubscription.swift; sourceTree = ""; }; + 88B1862928EF30A600D49854 /* YourVoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourVoteView.swift; sourceTree = ""; }; + 88B438E628F6C629001FC08A /* StatusTimeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTimeModel.swift; sourceTree = ""; }; 88BB219F28D34C660019C6B4 /* DataProviderChange+Identifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataProviderChange+Identifier.swift"; sourceTree = ""; }; 88C017E528C60A65003B2D28 /* AssetLockMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetLockMapper.swift; sourceTree = ""; }; 88C7165328C894510015D1E9 /* CollectionViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewDelegate.swift; sourceTree = ""; }; @@ -8338,6 +8362,7 @@ 847A25C028D84A3D006AC9F5 /* Governance */ = { isa = PBXGroup; children = ( + 880059D628EEA55500E87B9B /* View */, 84A1742528ED60610096F943 /* Operation */, 84D8753B28EB1796004065BD /* Model */, 8442002128E6FE0100C49C4A /* Referendums */, @@ -9644,7 +9669,6 @@ children = ( 88E8CF5D28E3789600C90112 /* CrowdloanEmptyView.swift */, 84BB3CF7267D276D00676FFE /* CrowdloanTableViewCell.swift */, - 8498430226592D29006BBB9F /* CrowdloanStatusSectionView.swift */, 88D997B128ABC90E006135A5 /* AboutCrowdloansView.swift */, 88D997AD28AB86FD006135A5 /* YourContributionsView.swift */, ); @@ -11078,10 +11102,13 @@ 84A1742328ED3CF70096F943 /* ReferendumLocal.swift */, 84DD49F528EE974B00B804F3 /* ReferendumDecidingFunctionProtocol.swift */, 84E9A04F28F000AB00551DC4 /* ReferendumMetadataLocal.swift */, + 8892284728F353A5003F8B9E /* ReferendumsModelFactory.swift */, + 8892284928F35410003F8B9E /* ReferendumsViewModel.swift */, 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */, 841221A528F13BA100715C82 /* GovernanceServiceFactory.swift */, 849707A028F3E0AC00DD0A02 /* ReferendumVoterLocal.swift */, 845B811C28F44A700040CE84 /* ReferendumActionLocal.swift */, + 88B438E628F6C629001FC08A /* StatusTimeModel.swift */, ); path = Model; sourceTree = ""; @@ -11098,6 +11125,7 @@ isa = PBXGroup; children = ( 888B853728ED966600AC9614 /* SkeletonableView.swift */, + 8498430226592D29006BBB9F /* VoteStatusSectionView.swift */, F4F69E272731B0B200214542 /* VoteTableHeaderView.swift */, ); path = View; @@ -11805,6 +11833,30 @@ path = ParaStkUnstakeConfirm; sourceTree = ""; }; + 880059D628EEA55500E87B9B /* View */ = { + isa = PBXGroup; + children = ( + 880059DD28EF093400E87B9B /* Slider */, + 880059E028EF0A5C00E87B9B /* VotingProgressView.swift */, + 880059E228EF128000E87B9B /* ReferendumInfoView.swift */, + 88B1862928EF30A600D49854 /* YourVoteView.swift */, + 889D889428F01E5B00C4320F /* ReferendumTableViewCell.swift */, + 889D889628F022AA00C4320F /* UILabel+Style.swift */, + ); + path = View; + sourceTree = ""; + }; + 880059DD28EF093400E87B9B /* Slider */ = { + isa = PBXGroup; + children = ( + 880059D728EEBC0200E87B9B /* SliderLayer.swift */, + 880059D928EF092800E87B9B /* ThumbLayer.swift */, + 880059DB28EF092F00E87B9B /* SegmentedSliderView.swift */, + 880059DE28EF09E100E87B9B /* GovernanceStyle.swift */, + ); + path = Slider; + sourceTree = ""; + }; 880855EE28D099BD004255E7 /* CrowdloanService */ = { isa = PBXGroup; children = ( @@ -14043,6 +14095,7 @@ 8428768824AE046300D91AD8 /* LanguageSelectionWireframe.swift in Sources */, 847F2D4227A96D9200AFD476 /* TokenGroupDecorationView.swift in Sources */, 849014E824AA925C008F705E /* ScrollsToTop.swift in Sources */, + 889D889528F01E5B00C4320F /* ReferendumTableViewCell.swift in Sources */, F41CEB83272FF3DD00C06154 /* CrowdloanYourContributionsVMFactory.swift in Sources */, 8490146A24A9463B008F705E /* Locale+Localization.swift in Sources */, 84DD5F64263DFAB700425ACF /* ErrorConditionViolation.swift in Sources */, @@ -14510,6 +14563,7 @@ 84333BDB285772F300C76A4F /* UInt64+TimeInterval.swift in Sources */, 847999AD2888646000D1BAD2 /* WatchOnlyWalletOperationFactory.swift in Sources */, 8472C5B4265CF9C500E2481B /* StakingRewardDestConfirmPresenter.swift in Sources */, + 880059DC28EF092F00E87B9B /* SegmentedSliderView.swift in Sources */, 8402CC9C275B92AC00E5BF30 /* ControlView.swift in Sources */, 2AB7A7FF25CD0E8000767D87 /* GitHubPhishingAPIService.swift in Sources */, AEF507F72625A3280098574D /* ValidatorState+Status.swift in Sources */, @@ -14663,6 +14717,7 @@ 8497FC6026317783002FEAA7 /* AccountInfoViewModel.swift in Sources */, 84DEE7042797FBF800B9A39E /* ExtrinsicExtension.swift in Sources */, 84B73AD4279B4D570071AE16 /* AssetAccount.swift in Sources */, + 880059DF28EF09E100E87B9B /* GovernanceStyle.swift in Sources */, 84DC3CE7279679230038E2ED /* SubqueryHistory+Wallet.swift in Sources */, 846A835828B8BC7B00D92892 /* LedgerTxConfirmViewController.swift in Sources */, 84BA1F7E27CE23C1000AAB82 /* NftChainModel.swift in Sources */, @@ -14803,6 +14858,7 @@ 845B811F28F451A40040CE84 /* Gov2ActionOperationFactory.swift in Sources */, 84754CA22513DB8800854599 /* EmptyAccountIcon.swift in Sources */, AEA0C8C6268131C500F9666F /* InitiatedBondingSelectedValidatorsListWireframe.swift in Sources */, + 880059E328EF128000E87B9B /* ReferendumInfoView.swift in Sources */, 84CE69922565244700559427 /* WalletAccountOpenCommand.swift in Sources */, 84F2FEFA25E797E8008338D5 /* StorageRequestFactory.swift in Sources */, 8468B87424F63D4B00B76BC6 /* AddAccount+AccountConfirmWireframe.swift in Sources */, @@ -14831,6 +14887,7 @@ 8441007C28A3CD5900DCCA11 /* ParitySignerScanInteractor.swift in Sources */, 84DA03D427592FAA00E8B326 /* ChainAccountView.swift in Sources */, 842B18082865923B0014CC57 /* XcmExtrinsicFeeProxy.swift in Sources */, + 889D889728F022AA00C4320F /* UILabel+Style.swift in Sources */, 843612C72790032400DC739E /* DAppOperationProcessedResult.swift in Sources */, 84DED410266659EC00A153BB /* CustomCrowdloanDelegate.swift in Sources */, 8418E7202617602000DCF6C8 /* WalletRemoteHistoryProtocols.swift in Sources */, @@ -14989,7 +15046,7 @@ 848077D22837CAE5003B7C79 /* ParachainStakingErrorPresentable.swift in Sources */, 84F4387025D9BC3900AEDA56 /* EmptyStreamableSource.swift in Sources */, 842A736F27DB7E57006EE1EA /* OperationExtrinsicViewModel.swift in Sources */, - 8498430326592D29006BBB9F /* CrowdloanStatusSectionView.swift in Sources */, + 8498430326592D29006BBB9F /* VoteStatusSectionView.swift in Sources */, 840D891D26242AE500AB231B /* StorageRequest.swift in Sources */, 8401AEC82642A71D000B03E3 /* StakingRebondConfirmationProtocols.swift in Sources */, 849014BA24AA87E4008F705E /* PinSetupProtocol.swift in Sources */, @@ -15104,6 +15161,7 @@ 84E172CF28BE468D00DC85B6 /* MessageSheetPresentable.swift in Sources */, 8487583727F06AF300495306 /* AddressScanDelegate.swift in Sources */, 3E480EEAF501AEB5D543506D /* UsernameSetupPresenter.swift in Sources */, + 880059DA28EF092800E87B9B /* ThumbLayer.swift in Sources */, 84F4387525D9C6EB00AEDA56 /* SubstrateDataProviderFactory.swift in Sources */, 841BFD6D27BA8E70000A16CE /* MetamaskSwitchChain.swift in Sources */, 84D2F1AC2774B3A00040C680 /* CustomSearchBar.swift in Sources */, @@ -15278,6 +15336,7 @@ 9DFB37659A6B911A4D54623E /* AccountConfirmInteractor.swift in Sources */, 84BAFCD626AF64CB00871E86 /* SelectValidatorsViewLayout.swift in Sources */, 84C5ADD52812745F006D7388 /* WalletAccountViewModel.swift in Sources */, + 8892284828F353A5003F8B9E /* ReferendumsModelFactory.swift in Sources */, 849A4EF2279A787200AB6709 /* AssetsUpdatingService.swift in Sources */, 84B018AC26E01A4100C75E28 /* StakingStateView.swift in Sources */, 842A737C27DCC489006EE1EA /* OperationDetailsTransferView.swift in Sources */, @@ -15330,6 +15389,7 @@ 84D8753D28EB17B2004065BD /* GovernanceSharedState.swift in Sources */, 8436EDE725895846004D9E97 /* PurchaseProvider.swift in Sources */, AEF50556261A04AD0098574D /* MoonpayProvider.swift in Sources */, + 880059D828EEBC0200E87B9B /* SliderLayer.swift in Sources */, 84FB29942639ABD700BE0FCD /* YourValidatorList+SelectionStart.swift in Sources */, 84DB9E8A26409E8200F23DD3 /* StakingRedeemLayout.swift in Sources */, 84F3B27627F4175500D64CF5 /* PhishingSite.swift in Sources */, @@ -16028,6 +16088,7 @@ 1D1DC32EFF13F41677A084B7 /* DAppOperationConfirmProtocols.swift in Sources */, 841E5561282E9CC700C8438F /* ParaStkStateMachineProtocols.swift in Sources */, 84720732277C370600F593DD /* DAppCategoriesView.swift in Sources */, + 8892284A28F35410003F8B9E /* ReferendumsViewModel.swift in Sources */, E2A9BC1477D81DDDE519404C /* DAppOperationConfirmWireframe.swift in Sources */, 88D997AE28AB86FE006135A5 /* YourContributionsView.swift in Sources */, 84ED6BDE28688CA500B3C558 /* TransferNetworkContainerView.swift in Sources */, @@ -16160,6 +16221,7 @@ 8217DCBEB74527D57AC82070 /* ParaStkStakeConfirmViewLayout.swift in Sources */, 06FD6F5999D57B27B29C8738 /* ParaStkStakeConfirmViewFactory.swift in Sources */, 2BBA744323AA0BF6FE53C212 /* ParaStkSelectCollatorsProtocols.swift in Sources */, + 880059E128EF0A5C00E87B9B /* VotingProgressView.swift in Sources */, 84744955289284F50042FD80 /* StakingMainViewLayout.swift in Sources */, 2BB0D54988107FA0C484C530 /* ParaStkSelectCollatorsWireframe.swift in Sources */, DEF53463C2C780D702E9C2CA /* ParaStkSelectCollatorsPresenter.swift in Sources */, @@ -16259,6 +16321,7 @@ 28B4C94DBAF461CBF18B1B63 /* WalletsListViewController.swift in Sources */, 233CB11F486DE1953D977295 /* WalletsListViewLayout.swift in Sources */, FD43B68CFBD5C3497B446F53 /* ChangeWatchOnlyProtocols.swift in Sources */, + 88B438E728F6C629001FC08A /* StatusTimeModel.swift in Sources */, E65FDA8BF9DBE7F50AE9D733 /* ChangeWatchOnlyWireframe.swift in Sources */, 02838B00DD7C9BC3BD78FF65 /* ChangeWatchOnlyPresenter.swift in Sources */, 493A9637BE5A1BF4B0744A4C /* ChangeWatchOnlyInteractor.swift in Sources */, @@ -16360,6 +16423,7 @@ 7C0135CA49EF6B535030643E /* ParaStkYieldBoostSetupPresenter.swift in Sources */, 21B297239CC294307EF20B58 /* ParaStkYieldBoostSetupInteractor.swift in Sources */, AE180C8B30831C9BAA39763A /* ParaStkYieldBoostSetupViewController.swift in Sources */, + 88B1862A28EF30A600D49854 /* YourVoteView.swift in Sources */, C19EF49636E698D87D5D18FA /* ParaStkYieldBoostSetupViewLayout.swift in Sources */, B3E567D46F54E8E735792FE1 /* ParaStkYieldBoostSetupViewFactory.swift in Sources */, E221892A5B6A41A944B88336 /* ParaStkYieldBoostStartProtocols.swift in Sources */, diff --git a/novawallet/Assets.xcassets/colorDarkGreen.colorset/Contents.json b/novawallet/Assets.xcassets/colorDarkGreen.colorset/Contents.json new file mode 100644 index 0000000000..303b6db44a --- /dev/null +++ b/novawallet/Assets.xcassets/colorDarkGreen.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x37", + "green" : "0xCF", + "red" : "0x15" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/colorDarkYellow.colorset/Contents.json b/novawallet/Assets.xcassets/colorDarkYellow.colorset/Contents.json new file mode 100644 index 0000000000..a258bc28af --- /dev/null +++ b/novawallet/Assets.xcassets/colorDarkYellow.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x0A", + "green" : "0xC5", + "red" : "0xEB" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/colorGreen24.colorset/Contents.json b/novawallet/Assets.xcassets/colorGreen24.colorset/Contents.json index 7345a0cf04..fbf30a4b8a 100644 --- a/novawallet/Assets.xcassets/colorGreen24.colorset/Contents.json +++ b/novawallet/Assets.xcassets/colorGreen24.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "0.240", - "blue" : "0.231", - "green" : "0.827", - "red" : "0.055" + "blue" : "0x3A", + "green" : "0xD2", + "red" : "0x0E" } }, "idiom" : "universal" diff --git a/novawallet/Assets.xcassets/colorRed40.colorset/Contents.json b/novawallet/Assets.xcassets/colorRed40.colorset/Contents.json index d8875167a6..abd37d824e 100644 --- a/novawallet/Assets.xcassets/colorRed40.colorset/Contents.json +++ b/novawallet/Assets.xcassets/colorRed40.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "0.400", - "blue" : "0.361", - "green" : "0.157", - "red" : "1.000" + "blue" : "0x5C", + "green" : "0x28", + "red" : "0xFF" } }, "idiom" : "universal" diff --git a/novawallet/Assets.xcassets/colorRedFF3A69.colorset/Contents.json b/novawallet/Assets.xcassets/colorRedFF3A69.colorset/Contents.json new file mode 100644 index 0000000000..aeb18d1dfb --- /dev/null +++ b/novawallet/Assets.xcassets/colorRedFF3A69.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x69", + "green" : "0x3A", + "red" : "0xFF" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/iconFire.imageset/Contents.json b/novawallet/Assets.xcassets/iconFire.imageset/Contents.json new file mode 100644 index 0000000000..29a2ceb48c --- /dev/null +++ b/novawallet/Assets.xcassets/iconFire.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Fire.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/iconFire.imageset/Fire.pdf b/novawallet/Assets.xcassets/iconFire.imageset/Fire.pdf new file mode 100644 index 0000000000000000000000000000000000000000..142adbb98c37abe2b0ba3b438440db33e1a9d6af GIT binary patch literal 2642 zcmd^BO>f&q5WVlO*o%SWkk#(&HxL+zKT)(nT&afuK@YUd*h(eQ73sq1ukRa@A|+W# z({p*Sm$Nf(XWnq<>E!0(>WxuR2qU$uZoddA-@cWT-@ZPUa`N%R?U!=iz=mh?OS!&p z9wfnW+MBL7)zjlnK>Ob9wJ}}b40xMjT|X9^ay|dLw|{!tL(QIUoA%JFYP0HX)3UCf zHuJLPBL>g2v+7xXl3MBZ85bsOP2=i!Kq0bjHf6CAlZ*1N#k`zepULyt?%TW;e+sh= zAE4h1t6`5+us)EMM)_o24syN{T4mD7TI3R=HQsYlHrbG5Jzoo}G-VT z69MFsNxI#oOwM{qDkbL}!x(KX7EUFtjni`826|6P21Uk2?SWuD5%8n3!TXdM(>Vml zgoL8A5phN(PXU_=x!I^Kj?o10ggBR@(}^u18?wNTq{$e>S%9VtucWM@7%Y+@irL^` zt-OiO5SwC(F-e2mttC&0JYtM01f*j*G&!3Q5m9X5da$sdiEB*C#F&%AnaIy0GaODR z*2s*~$V4s;WsnODrDNvGI56wzGxcsD%s5o(DQam|Ok}fVnm~@XJN@8DpF_4895@%r zup8&9v-B#u492imsL4h;KMz*XhDrddNC!BML^FIw-FyMib3~C zq4y3&kRojf31a}56wt*ZAL?8@h|gjzeifoz-}UzhE1ngCXF)eK5@p_Rt+)n1HcH(8 zdz7>j#6}1HcSp(LSQ};#kCNeKyk{%XtuZHdZr^gpI*y&?2yoOmqAtJJcWzwQcg&BW z?-*A*eecDiRfms8vc62mA%6MXT+f=KDck)^)Bc;iFX}(qRi{7vx~CSSsO+yM*OEWF zUY7RvUc619NAH%855>PjZ#Cxy1{->j94h%1-05joHo&$wBiF$sz^+R!3`eKI$U6USy{?*Ceqxy%OS&oU%ii$5yjv9iRd5+;)NcMPwm%ro zt94VZaUwIYHQw;=f=1@vw8Imdx(YbipBHyXRdNMWxy|^zdP1yuk$(-#4id)QE)-W- z4=0Y5pBGKBtnT+?pEu=afhlQ3cQyI1gw8^!VecP4fFFrF+CD}nG=QJcWFRI7CZBOL z_PqkM=fISq#QP@5(4iNmIWFcN7Lh(of>;i=Ud^UhEX$2xdVjhAxv%PKRlb(57I&{Z liYL>m0>4aO+po!N@ps8wfZVz%HciV8#()tgCzl_t{sAtZJTL$N literal 0 HcmV?d00001 diff --git a/novawallet/Common/Extension/Foundation/DateFormatter.swift b/novawallet/Common/Extension/Foundation/DateFormatter.swift index c0ef02b587..2a1393cfe2 100644 --- a/novawallet/Common/Extension/Foundation/DateFormatter.swift +++ b/novawallet/Common/Extension/Foundation/DateFormatter.swift @@ -32,3 +32,18 @@ extension DateFormatter { } } } + +extension DateComponentsFormatter { + static var fullTime: LocalizableResource { + LocalizableResource { locale in + var calendar = Calendar.current + calendar.locale = locale + let dateFormatter = DateComponentsFormatter() + dateFormatter.allowedUnits = [.hour, .minute, .second] + dateFormatter.unitsStyle = .positional + dateFormatter.calendar = calendar + + return dateFormatter + } + } +} diff --git a/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift b/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift index cdcfc415c2..b2a792a5be 100644 --- a/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift +++ b/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift @@ -25,6 +25,20 @@ extension TimeInterval { return components.joined(separator: " ") } + + func localizedDaysOrTime(for locale: Locale) -> String? { + let days = daysFromSeconds + + if days > 0 { + let daysString = R.string.localizable.commonDaysFormat( + format: days, preferredLanguages: locale.rLanguages + ) + return daysString + } else { + let formatter = DateComponentsFormatter.fullTime + return formatter.value(for: locale).string(from: self) + } + } } extension UInt { diff --git a/novawallet/Common/ViewModel/TitleIconViewModel.swift b/novawallet/Common/ViewModel/TitleIconViewModel.swift index b6cdc4bb61..d1a59836c1 100644 --- a/novawallet/Common/ViewModel/TitleIconViewModel.swift +++ b/novawallet/Common/ViewModel/TitleIconViewModel.swift @@ -1,6 +1,6 @@ import UIKit -struct TitleIconViewModel { +struct TitleIconViewModel: Equatable { let title: String let icon: UIImage? } diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift index b485249291..df718546e8 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListViewManager.swift @@ -110,7 +110,7 @@ extension CrowdloanListViewManager: UITableViewDelegate { let sectionModel = viewModel.sections[section] switch sectionModel { case let .active(title, cells), let .completed(title, cells): - let headerView: CrowdloanStatusSectionView = tableView.dequeueReusableHeaderFooterView() + let headerView: VoteStatusSectionView = tableView.dequeueReusableHeaderFooterView() switch title { case let .loaded(value): headerView.bind(viewModel: .loaded(value: .init(title: value, count: cells.count))) @@ -121,7 +121,7 @@ extension CrowdloanListViewManager: UITableViewDelegate { } return headerView case let .empty(title): - let headerView: CrowdloanStatusSectionView = tableView.dequeueReusableHeaderFooterView() + let headerView: VoteStatusSectionView = tableView.dequeueReusableHeaderFooterView() headerView.bind(viewModel: .loaded(value: .init(title: title, count: 0))) return headerView default: @@ -223,7 +223,7 @@ extension CrowdloanListViewManager: VoteChildViewProtocol { tableView.registerClassForCell(CrowdloanTableViewCell.self) tableView.registerClassForCell(BlurredTableViewCell.self) tableView.registerClassForCell(BlurredTableViewCell.self) - tableView.registerHeaderFooterView(withClass: CrowdloanStatusSectionView.self) + tableView.registerHeaderFooterView(withClass: VoteStatusSectionView.self) tableView.dataSource = self tableView.delegate = self @@ -237,7 +237,7 @@ extension CrowdloanListViewManager: VoteChildViewProtocol { tableView.unregisterClassForCell(CrowdloanTableViewCell.self) tableView.unregisterClassForCell(BlurredTableViewCell.self) tableView.unregisterClassForCell(BlurredTableViewCell.self) - tableView.unregisterHeaderFooterView(withClass: CrowdloanStatusSectionView.self) + tableView.unregisterHeaderFooterView(withClass: VoteStatusSectionView.self) tableView.dataSource = nil tableView.delegate = nil diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumsModelFactory.swift new file mode 100644 index 0000000000..af988fe990 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumsModelFactory.swift @@ -0,0 +1,570 @@ +import Foundation +import SoraFoundation +import BigInt + +struct ReferendumsModelFactoryInput { + let referendums: [ReferendumLocal] + let metadataMapping: [Referenda.ReferendumIndex: ReferendumMetadataLocal]? + let votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal] + let chainInfo: ChainInformation + let locale: Locale + + struct ChainInformation { + let chain: ChainModel + let currentBlock: BlockNumber + let blockDurartion: UInt64 + } +} + +protocol ReferendumsModelFactoryProtocol { + func createSections(input: ReferendumsModelFactoryInput) -> [ReferendumsSection] + + func createTimeModels( + referendums: [ReferendumLocal], + currentBlock: BlockNumber, + blockDurartion: UInt64, + locale: Locale + ) -> [UInt: StatusTimeModel?] +} + +final class ReferendumsModelFactory { + private typealias Input = ReferendumsModelFactoryInput + private typealias Strings = R.string.localizable + + let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol + let percentFormatter: NumberFormatter + let referendumNumberFormatter: NumberFormatter + init( + assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, + percentFormatter: NumberFormatter, + referendumNumberFormatter: NumberFormatter + ) { + self.assetBalanceFormatterFactory = assetBalanceFormatterFactory + self.percentFormatter = percentFormatter + self.referendumNumberFormatter = referendumNumberFormatter + } + + private func provideCommonReferendumCellViewModel( + status: ReferendumInfoView.Model.Status, + metadata: ReferendumMetadataLocal?, + votes: ReferendumAccountVoteLocal?, + chain: ChainModel, + locale: Locale + ) -> ReferendumView.Model { + let yourVotesModel = createVotesViewModel( + votes: votes, + chainAsset: chain.utilityAsset(), + locale: locale + ) + return .init( + referendumInfo: .init( + status: status, + time: nil, + title: metadata?.name ?? "", + track: nil + ), + progress: nil, + yourVotes: yourVotesModel + ) + } + + private func providePreparingReferendumCellViewModel( + _ model: ReferendumStateLocal.Preparing, + referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + votes: ReferendumAccountVoteLocal?, + chainInfo: Input.ChainInformation, + locale: Locale + ) -> ReferendumView.Model { + let timeModel = createTimeModel( + for: referendum, + currentBlock: chainInfo.currentBlock, + blockDurartion: chainInfo.blockDurartion, + locale: locale + ) + + let title = model.inQueue ? + Strings.governanceReferendumsStatusPreparingInqueue(preferredLanguages: locale.rLanguages) : + Strings.governanceReferendumsStatusPreparing(preferredLanguages: locale.rLanguages) + + switch model.voting { + case let .supportAndVotes(supportAndVotes): + let progressViewModel = createVotingProgressViewModel( + supportAndVotes: supportAndVotes, + chain: chainInfo.chain, + currentBlock: chainInfo.currentBlock, + locale: locale + ) + let yourVotesModel = createVotesViewModel( + votes: votes, + chainAsset: chainInfo.chain.utilityAsset(), + locale: locale + ) + let trackName = model.track.name.replacingSnakeCase().uppercased() + let referendumNumber = referendumNumberFormatter.string(from: NSNumber(value: referendum.index)) + + return .init( + referendumInfo: .init( + status: .init(name: title.uppercased(), kind: .neutral), + time: timeModel?.viewModel, + title: metadata?.name ?? "", + track: .init( + titleIcon: .init(title: trackName, icon: nil), + referendumNumber: referendumNumber.map { "#" + $0 } + ) + ), + progress: progressViewModel, + yourVotes: yourVotesModel + ) + } + } + + private func createVotesViewModel( + votes: ReferendumAccountVoteLocal?, + chainAsset: AssetModel?, + locale: Locale + ) -> YourVotesView.Model? { + guard let votes = votes, + let chainAsset = chainAsset, + votes.ayes + votes.nays > 0 else { + return nil + } + + let inputFormatter = assetBalanceFormatterFactory.createInputFormatter(for: chainAsset.displayInfo) + + let formatVotes: (BigUInt) -> String = { votesInPlank in + guard let votes = Decimal.fromSubstrateAmount( + votesInPlank, + precision: Int16(chainAsset.precision) + ) else { + return "" + } + let votesString = inputFormatter.value(for: locale).stringFromDecimal(votes) ?? "" + return Strings.governanceReferendumsYourVote( + votesString, + preferredLanguages: locale.rLanguages + ) + } + let ayesModel = votes.ayes > 0 ? YourVoteView.Model( + title: "AYE", + description: formatVotes(votes.ayes) + ) : nil + let naysModel = votes.nays > 0 ? YourVoteView.Model( + title: "NAY", + description: formatVotes(votes.nays) + ) : nil + return .init( + aye: ayesModel, + nay: naysModel + ) + } + + private func provideDecidingReferendumCellViewModel( + _ model: ReferendumStateLocal.Deciding, + referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + chainInfo: Input.ChainInformation, + votes: ReferendumAccountVoteLocal?, + locale: Locale + ) -> ReferendumView.Model { + switch model.voting { + case let .supportAndVotes(supportAndVotes): + let timeModel: StatusTimeModel? + if supportAndVotes.isPassing(at: chainInfo.currentBlock), + let confirmationUntil = model.confirmationUntil { + timeModel = createTimeModel( + state: referendum.state, + atBlock: confirmationUntil, + currentBlock: chainInfo.currentBlock, + blockDuration: chainInfo.blockDurartion, + timeStringProvider: Strings.governanceReferendumsTimeApprove, + locale: locale + ) + } else { + timeModel = createTimeModel( + state: referendum.state, + atBlock: model.period, + currentBlock: chainInfo.currentBlock, + blockDuration: chainInfo.blockDurartion, + timeStringProvider: Strings.governanceReferendumsTimeReject, + locale: locale + ) + } + + let progressViewModel = createVotingProgressViewModel( + supportAndVotes: supportAndVotes, + chain: chainInfo.chain, + currentBlock: chainInfo.currentBlock, + locale: locale + ) + let isPassing = supportAndVotes.isPassing(at: chainInfo.currentBlock) + let statusName = isPassing ? + Strings.governanceReferendumsStatusPassing(preferredLanguages: locale.rLanguages) : + Strings.governanceReferendumsStatusNotPassing(preferredLanguages: locale.rLanguages) + let statusKind: ReferendumInfoView.Model.StatusKind = isPassing ? .positive : .negative + let yourVotesModel = createVotesViewModel( + votes: votes, + chainAsset: chainInfo.chain.utilityAsset(), + locale: locale + ) + let trackName = model.track.name.replacingSnakeCase().uppercased() + let referendumNumber = referendumNumberFormatter.string(from: NSNumber(value: referendum.index)) + + return .init( + referendumInfo: .init( + status: .init(name: statusName.uppercased(), kind: statusKind), + time: timeModel?.viewModel, + title: metadata?.name, + track: .init( + titleIcon: .init(title: trackName, icon: nil), + referendumNumber: referendumNumber.map { "#" + $0 } + ) + ), + progress: progressViewModel, + yourVotes: yourVotesModel + ) + } + } + + private func provideApprovedReferendumCellViewModel( + _ model: ReferendumStateLocal.Approved, + referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + chainInfo: Input.ChainInformation, + votes: ReferendumAccountVoteLocal?, + locale: Locale + ) -> ReferendumView.Model { + let timeModel: StatusTimeModel? + if let whenEnactment = model.whenEnactment { + timeModel = createTimeModel( + state: referendum.state, + atBlock: whenEnactment, + currentBlock: chainInfo.currentBlock, + blockDuration: chainInfo.blockDurartion, + timeStringProvider: Strings.governanceReferendumsTimeExecute, + locale: locale + ) + } else { + timeModel = nil + } + + let title = Strings.governanceReferendumsStatusApproved(preferredLanguages: locale.rLanguages) + let yourVotesModel = createVotesViewModel( + votes: votes, + chainAsset: chainInfo.chain.utilityAsset(), + locale: locale + ) + return .init( + referendumInfo: .init( + status: .init(name: title.uppercased(), kind: .positive), + time: timeModel?.viewModel, + title: metadata?.name, + track: nil + ), + progress: nil, + yourVotes: yourVotesModel + ) + } + + private func createVotingProgressViewModel( + supportAndVotes: SupportAndVotesLocal, + chain: ChainModel, + currentBlock: BlockNumber, + locale: Locale + ) -> VotingProgressView.Model { + let ayeProgress = percentFormatter.stringFromDecimal(supportAndVotes.approvalFraction) ?? "" + let nayProgress = percentFormatter.stringFromDecimal(1 - supportAndVotes.approvalFraction) ?? "" + let passProgress = percentFormatter.stringFromDecimal(supportAndVotes.supportFraction) ?? "" + let thresholdModel: VotingProgressView.ThresholdModel? + if let chainAsset = chain.utilityAsset(), + let supportThreshold = supportAndVotes.supportFunction?.calculateThreshold(for: currentBlock) { + let targetThreshold = Decimal.fromSubstrateAmount( + supportAndVotes.totalIssuance, + precision: Int16(chainAsset.precision) + ) + let threshold = Decimal.fromSubstrateAmount( + supportAndVotes.support, + precision: Int16(chainAsset.precision) + ) + let isCompleted = supportAndVotes.supportFraction >= supportThreshold + + let image = isCompleted ? + R.image.iconCheckmark()?.withTintColor(R.color.colorDarkGreen()!) : + R.image.iconClose()?.withTintColor(R.color.colorRedFF3A69()!) + let tokenFormatter = assetBalanceFormatterFactory.createTokenFormatter(for: chainAsset.displayInfo) + + let targetThresholdString = targetThreshold.map { + tokenFormatter.value(for: locale).stringFromDecimal($0) ?? "" + } ?? "" + let thresholdString = threshold.map(String.init) ?? "" + let text = R.string.localizable.governanceReferendumsThreshold(thresholdString, targetThresholdString) + thresholdModel = .init( + titleIcon: .init(title: text, icon: image), + value: supportAndVotes.supportFraction + ) + } else { + thresholdModel = nil + } + + return .init( + ayeProgress: "Aye: \(ayeProgress)", + passProgress: "To pass: \(passProgress)", + nayProgress: "Nay: \(nayProgress)", + thresholdModel: thresholdModel, + progress: supportAndVotes.approvalFraction + ) + } + + private func createTimeModel( + for referendum: ReferendumLocal, + currentBlock: BlockNumber, + blockDurartion: UInt64, + locale: Locale + ) -> StatusTimeModel? { + let strings = R.string.localizable.self + switch referendum.state { + case let .preparing(model): + if model.deposit == nil { + let title = strings.governanceReferendumsTimeWaitingDeposit(preferredLanguages: locale.rLanguages) + let timeViewModel = ReferendumInfoView.Model.Time( + titleIcon: .init(title: title, icon: R.image.iconLightPending()), + isUrgent: false + ) + + return StatusTimeModel(viewModel: timeViewModel, timeInterval: nil) { _ in + timeViewModel + } + } else { + return createTimeModel( + state: referendum.state, + atBlock: model.since, + currentBlock: currentBlock, + blockDuration: blockDurartion, + timeStringProvider: strings.governanceReferendumsTimeDeciding, + locale: locale + ) + } + case let .deciding(model): + switch model.voting { + case let .supportAndVotes(supportAndVotes): + if supportAndVotes.isPassing(at: currentBlock), + let confirmationUntil = model.confirmationUntil { + return createTimeModel( + state: referendum.state, + atBlock: confirmationUntil, + currentBlock: currentBlock, + blockDuration: blockDurartion, + timeStringProvider: strings.governanceReferendumsTimeApprove, + locale: locale + ) + } else { + return createTimeModel( + state: referendum.state, + atBlock: model.period, + currentBlock: currentBlock, + blockDuration: blockDurartion, + timeStringProvider: strings.governanceReferendumsTimeReject, + locale: locale + ) + } + } + case let .approved(model): + guard let whenEnactment = model.whenEnactment else { + return nil + } + return createTimeModel( + state: referendum.state, + atBlock: whenEnactment, + currentBlock: currentBlock, + blockDuration: blockDurartion, + timeStringProvider: strings.governanceReferendumsTimeExecute, + locale: locale + ) + case .rejected, .cancelled, .timedOut, .killed, .executed: + return nil + } + } + + private func createTimeModel( + state: ReferendumStateLocal, + atBlock: Moment, + currentBlock: BlockNumber, + blockDuration: UInt64, + timeStringProvider: @escaping (String, [String]?) -> String, + locale: Locale + ) -> StatusTimeModel? { + let time = calculateTime( + block: atBlock, + currentBlock: currentBlock, + blockDuration: blockDuration + ) + guard let timeModel = createTimeModel( + time: time, + timeStringProvider: timeStringProvider, + state: state, + locale: locale + ) else { + return nil + } + return .init(viewModel: timeModel, timeInterval: time) { [weak self] in + self?.createTimeModel( + time: $0, + timeStringProvider: timeStringProvider, + state: state, + locale: locale + ) + } + } + + private func createTimeModel( + time: TimeInterval, + timeStringProvider: (String, [String]?) -> String, + state: ReferendumStateLocal, + locale: Locale + ) -> ReferendumInfoView.Model.Time? { + guard let localizedDaysHours = time.localizedDaysOrTime(for: locale) else { + return nil + } + let timeString = timeStringProvider(localizedDaysHours, locale.rLanguages) + let timeModel = isUrgent(state: state, time: time).map { isUrgent in + ReferendumInfoView.Model.Time( + titleIcon: .init( + title: timeString, + icon: isUrgent ? R.image.iconFire() : R.image.iconLightPending() + ), + isUrgent: isUrgent + ) + } + return timeModel + } + + private func calculateTime(block: Moment, currentBlock: BlockNumber, blockDuration: UInt64) -> TimeInterval { + currentBlock.secondsTo(block: block, blockDuration: blockDuration) + } + + private func isUrgent(state: ReferendumStateLocal, time: TimeInterval) -> Bool? { + switch state { + case .preparing: + return time.hoursFromSeconds <= 3 + case .deciding: + return time.daysFromSeconds < 1 + case .approved: + return time.daysFromSeconds < 1 + case .rejected: + return time.daysFromSeconds < 1 + case .cancelled, .timedOut, .killed, .executed: return nil + } + } +} + +extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { + func createTimeModels( + referendums: [ReferendumLocal], + currentBlock: BlockNumber, + blockDurartion: UInt64, + locale: Locale + ) -> [UInt: StatusTimeModel?] { + referendums.reduce(into: [UInt: StatusTimeModel?]()) { result, referendum in + result[referendum.index] = createTimeModel( + for: referendum, + currentBlock: currentBlock, + blockDurartion: blockDurartion, + locale: locale + ) + } + } + + func createSections(input: ReferendumsModelFactoryInput) -> [ReferendumsSection] { + var active: [ReferendumsCellViewModel] = [] + var completed: [ReferendumsCellViewModel] = [] + + input.referendums.forEach { referendum in + let index = Referenda.ReferendumIndex(referendum.index) + let metadata = input.metadataMapping?[index] + let model = createReferendumsCellViewModel( + referendum: referendum, + metadata: metadata, + chainInformation: input.chainInfo, + votes: input.votes[index], + locale: input.locale + ) + let viewModel = ReferendumsCellViewModel( + referendumIndex: referendum.index, + viewModel: .loaded(value: model) + ) + referendum.state.completed ? completed.append(viewModel) : active.append(viewModel) + } + var sections: [ReferendumsSection] = [] + if !active.isEmpty { + let title = Strings.governanceReferendumsActive(preferredLanguages: input.locale.rLanguages) + sections.append(.active(.loaded(value: title), active)) + } + if !completed.isEmpty { + let title = Strings.governanceReferendumsCompleted(preferredLanguages: input.locale.rLanguages) + sections.append(.completed(.loaded(value: title), completed)) + } + return sections + } + + private func createReferendumsCellViewModel( + referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + chainInformation: Input.ChainInformation, + votes: ReferendumAccountVoteLocal?, + locale: Locale + ) -> ReferendumView.Model { + let status: ReferendumInfoView.Model.Status + switch referendum.state { + case let .preparing(model): + return providePreparingReferendumCellViewModel( + model, + referendum: referendum, + metadata: metadata, + votes: votes, + chainInfo: chainInformation, + locale: locale + ) + case let .deciding(model): + return provideDecidingReferendumCellViewModel( + model, + referendum: referendum, + metadata: metadata, + chainInfo: chainInformation, + votes: votes, + locale: locale + ) + case let .approved(model): + return provideApprovedReferendumCellViewModel( + model, + referendum: referendum, + metadata: metadata, + chainInfo: chainInformation, + votes: votes, + locale: locale + ) + case .rejected: + let statusName = Strings.governanceReferendumsStatusRejected(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .negative) + case .cancelled: + let statusName = Strings.governanceReferendumsStatusCancelled(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .neutral) + case .timedOut: + let statusName = Strings.governanceReferendumsStatusTimedOut(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .neutral) + case .killed: + let statusName = Strings.governanceReferendumsStatusKilled(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .negative) + case .executed: + let statusName = Strings.governanceReferendumsStatusExecuted(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .positive) + } + + return provideCommonReferendumCellViewModel( + status: status, + metadata: metadata, + votes: votes, + chain: chainInformation.chain, + locale: locale + ) + } +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumsViewModel.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumsViewModel.swift new file mode 100644 index 0000000000..5a98452737 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumsViewModel.swift @@ -0,0 +1,13 @@ +struct ReferendumsViewModel { + let sections: [ReferendumsSection] +} + +enum ReferendumsSection { + case active(LoadableViewModelState, [ReferendumsCellViewModel]) + case completed(LoadableViewModelState, [ReferendumsCellViewModel]) +} + +struct ReferendumsCellViewModel { + var referendumIndex: UInt + var viewModel: LoadableViewModelState +} diff --git a/novawallet/Modules/Vote/Governance/Model/StatusTimeModel.swift b/novawallet/Modules/Vote/Governance/Model/StatusTimeModel.swift new file mode 100644 index 0000000000..f4cb8ad670 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/StatusTimeModel.swift @@ -0,0 +1,7 @@ +import Foundation + +struct StatusTimeModel { + let viewModel: ReferendumInfoView.Model.Time + let timeInterval: TimeInterval? + let updateModelClosure: (TimeInterval) -> ReferendumInfoView.Model.Time? +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 54d1eb4d0c..8f3ed3e368 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -16,18 +16,25 @@ final class ReferendumsPresenter { private var referendumsMetadata: ReferendumMetadataMapping? private var votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]? private var blockNumber: BlockNumber? + private let viewModelFactory: ReferendumsModelFactoryProtocol private var blockTime: BlockTime? + private var maxStatusTimeInterval: TimeInterval? + private var countdownTimer: CountdownTimer? + private var timeModels: [UInt: StatusTimeModel?]? + private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() init( interactor: ReferendumsInteractorInputProtocol, wireframe: ReferendumsWireframeProtocol, + viewModelFactory: ReferendumsModelFactoryProtocol, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol ) { self.interactor = interactor self.wireframe = wireframe + self.viewModelFactory = viewModelFactory self.logger = logger self.localizationManager = localizationManager } @@ -45,6 +52,107 @@ final class ReferendumsPresenter { view?.didReceiveChainBalance(viewModel: viewModel) } + + private func updateView() { + guard let view = view else { + return + } + guard let currentBlock = blockNumber, + let blockTime = blockTime, + let referendums = referendums, + let chainModel = chain else { + return + } + let sections = viewModelFactory.createSections(input: .init( + referendums: referendums, + metadataMapping: referendumsMetadata, + votes: votes ?? [:], + chainInfo: .init(chain: chainModel, currentBlock: currentBlock, blockDurartion: blockTime), + locale: selectedLocale + )) + + view.update(model: .init(sections: sections)) + } + + private func updateTimeModels() { + guard let view = view else { + return + } + guard let currentBlock = blockNumber, + let blockTime = blockTime, + let referendums = referendums else { + return + } + + let timeModels = viewModelFactory.createTimeModels( + referendums: referendums, + currentBlock: currentBlock, + blockDurartion: blockTime, + locale: selectedLocale + ) + + self.timeModels = timeModels + maxStatusTimeInterval = timeModels.compactMap { $0.value?.timeInterval }.max(by: <) + invalidateTimer() + setupTimer() + updateTimerDisplay() + + view.updateReferendums(time: timeModels) + } + + private func invalidateTimer() { + countdownTimer?.stop() + countdownTimer = nil + } + + private func setupTimer() { + guard let maxStatusTimeInterval = maxStatusTimeInterval else { + return + } + + countdownTimer = CountdownTimer() + countdownTimer?.delegate = self + countdownTimer?.start(with: maxStatusTimeInterval) + } + + private func updateTimerDisplay() { + guard + let view = view, + let maxStatusTimeInterval = maxStatusTimeInterval, + let remainedTimeInterval = countdownTimer?.remainedInterval, + let timeModels = timeModels else { + return + } + + let elapsedTime = maxStatusTimeInterval >= remainedTimeInterval ? + maxStatusTimeInterval - remainedTimeInterval : 0 + + let updatedTimeModels = timeModels.reduce(into: timeModels) { result, model in + guard let timeModel = model.value, + let time = timeModel.timeInterval else { + return + } + + guard time > elapsedTime else { + result[model.key] = nil + return + } + let remainedTime = time - elapsedTime + guard let updatedViewModel = timeModel.updateModelClosure(remainedTime) else { + result[model.key] = nil + return + } + + result[model.key] = .init( + viewModel: updatedViewModel, + timeInterval: remainedTime, + updateModelClosure: timeModel.updateModelClosure + ) + } + + self.timeModels = updatedTimeModels + view.updateReferendums(time: updatedTimeModels) + } } extension ReferendumsPresenter: ReferendumsPresenterProtocol {} @@ -84,26 +192,31 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) { referendumsMetadata = metadata + updateView() } func didReceiveBlockNumber(_ blockNumber: BlockNumber) { self.blockNumber = blockNumber interactor.refresh() + updateTimeModels() } func didReceiveBlockTime(_ blockTime: BlockTime) { self.blockTime = blockTime + updateTimeModels() } func didReceiveReferendums(_ referendums: [ReferendumLocal]) { - self.referendums = referendums + self.referendums = referendums.sorted(by: { $0.index < $1.index }) + updateView() } func didReceiveSelectedChain(_ chain: ChainModel) { self.chain = chain provideChainBalance() + updateView() } func didReceiveAssetBalance(_ balance: AssetBalance?) { @@ -167,6 +280,22 @@ extension ReferendumsPresenter: Localizable { func applyLocalization() { if let view = view, view.isSetup { provideChainBalance() + + updateView() } } } + +extension ReferendumsPresenter: CountdownTimerDelegate { + func didStart(with _: TimeInterval) { + updateTimerDisplay() + } + + func didCountdown(remainedInterval _: TimeInterval) { + updateTimerDisplay() + } + + func didStop(with _: TimeInterval) { + updateTimerDisplay() + } +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 0b71e0be24..61621d5866 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -4,6 +4,8 @@ protocol ReferendumsViewProtocol: ControllerBackedProtocol { var presenter: ReferendumsPresenterProtocol? { get set } func didReceiveChainBalance(viewModel: ChainBalanceViewModel) + func update(model: ReferendumsViewModel) + func updateReferendums(time: [UInt: StatusTimeModel?]) } protocol ReferendumsPresenterProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 17342cf48a..1a738cf69a 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -4,6 +4,7 @@ import UIKit final class ReferendumsViewManager: NSObject { let tableView: UITableView let chainSelectionView: VoteChainViewProtocol + private var model: ReferendumsViewModel = .init(sections: []) var locale = Locale.current { didSet { @@ -25,18 +26,28 @@ final class ReferendumsViewManager: NSObject { } } -// TODO: Implement protocols when data source defined extension ReferendumsViewManager: UITableViewDataSource { func numberOfSections(in _: UITableView) -> Int { - 0 + model.sections.count } - func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { - 0 + func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { + switch model.sections[section] { + case let .active(_, cells), let .completed(_, cells): + return cells.count + } } - func tableView(_: UITableView, cellForRowAt _: IndexPath) -> UITableViewCell { - UITableViewCell() + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell: ReferendumTableViewCell = tableView.dequeueReusableCell(for: indexPath) + cell.applyStyle() + let section = model.sections[indexPath.section] + switch section { + case let .active(_, cellModels), let .completed(_, cellModels): + let cellModel = cellModels[indexPath.row].viewModel + cell.view.bind(viewModel: cellModel) + return cell + } } } @@ -45,12 +56,25 @@ extension ReferendumsViewManager: UITableViewDelegate { tableView.deselectRow(at: indexPath, animated: true) } - func tableView(_: UITableView, viewForHeaderInSection _: Int) -> UIView? { - nil + func tableView(_: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let sectionModel = model.sections[section] + switch sectionModel { + case let .active(title, cells), let .completed(title, cells): + let headerView: VoteStatusSectionView = tableView.dequeueReusableHeaderFooterView() + switch title { + case let .loaded(value): + headerView.bind(viewModel: .loaded(value: .init(title: value, count: cells.count))) + case let .cached(value): + headerView.bind(viewModel: .cached(value: .init(title: value, count: cells.count))) + case .loading: + headerView.bind(viewModel: .loading) + } + return headerView + } } func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat { - 0.0 + UITableView.automaticDimension } } @@ -58,6 +82,30 @@ extension ReferendumsViewManager: ReferendumsViewProtocol { func didReceiveChainBalance(viewModel: ChainBalanceViewModel) { chainSelectionView.bind(viewModel: viewModel) } + + func update(model: ReferendumsViewModel) { + self.model = model + tableView.reloadData() + } + + func updateReferendums(time: [UInt: StatusTimeModel?]) { + tableView.visibleCells.forEach { cell in + guard let referendumCell = cell as? ReferendumTableViewCell, + let indexPath = tableView.indexPath(for: cell) else { + return + } + + switch model.sections[indexPath.section] { + case let .active(_, cells), let .completed(_, cells): + let cellModel = cells[indexPath.row] + guard let timeModel = time[cellModel.referendumIndex]??.viewModel else { + return + } + + referendumCell.view.referendumInfoView.bind(timeModel: timeModel) + } + } + } } extension ReferendumsViewManager: VoteChildViewProtocol { @@ -72,14 +120,16 @@ extension ReferendumsViewManager: VoteChildViewProtocol { func bind() { tableView.dataSource = self tableView.delegate = self - + tableView.registerClassForCell(ReferendumTableViewCell.self) + tableView.registerHeaderFooterView(withClass: VoteStatusSectionView.self) tableView.reloadData() } func unbind() { tableView.dataSource = nil tableView.delegate = nil - + tableView.unregisterClassForCell(ReferendumTableViewCell.self) + tableView.unregisterHeaderFooterView(withClass: VoteStatusSectionView.self) tableView.reloadData() } } diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift new file mode 100644 index 0000000000..b4e4561881 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -0,0 +1,172 @@ +import UIKit +import SoraUI + +final class ReferendumInfoView: UIView { + let statusLabel: UILabel = .init(style: .neutralStatusLabel) + + let timeView: IconDetailsView = .create { + $0.mode = .detailsIcon + $0.detailsLabel.numberOfLines = 1 + $0.spacing = 5 + $0.apply(style: .timeView) + } + + let titleLabel: UILabel = .init(style: .title) + + let trackNameView: BorderedIconLabelView = .create { + $0.iconDetailsView.spacing = 6 + $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) + $0.iconDetailsView.detailsLabel.apply(style: .track) + $0.backgroundView.apply(style: .referendum) + $0.iconDetailsView.detailsLabel.numberOfLines = 1 + } + + let numberLabel: BorderedLabelView = .create { + $0.titleLabel.apply(style: .track) + $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) + $0.backgroundView.apply(style: .referendum) + $0.titleLabel.numberOfLines = 1 + } + + lazy var trackInformation: UIStackView = UIView.hStack( + spacing: 6, + [ + trackNameView, + numberLabel, + UIView() + ] + ) + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.vStack( + spacing: 8, + [ + UIView.hStack([ + statusLabel, + UIView(), + timeView + ]), + titleLabel, + trackInformation + ] + ) + content.setCustomSpacing(12, after: titleLabel) + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } +} + +extension ReferendumInfoView { + struct Model { + let status: Status + let time: Time? + let title: String? + let track: Track? + + struct Time: Equatable { + let titleIcon: TitleIconViewModel + let isUrgent: Bool + } + + struct Track { + let titleIcon: TitleIconViewModel + let referendumNumber: String? + } + + struct Status { + let name: String + let kind: StatusKind + } + + enum StatusKind { + case positive + case negative + case neutral + } + } + + func bind(viewModel: Model) { + trackInformation.isHidden = viewModel.track == nil + numberLabel.isHidden = viewModel.track?.referendumNumber == nil + + titleLabel.text = viewModel.title + trackNameView.iconDetailsView.bind(viewModel: viewModel.track?.titleIcon) + numberLabel.titleLabel.text = viewModel.track?.referendumNumber + statusLabel.text = viewModel.status.name + bind(timeModel: viewModel.time) + + switch viewModel.status.kind { + case .positive: + statusLabel.apply(style: .positiveStatusLabel) + case .negative: + statusLabel.apply(style: .negativeStatusLabel) + case .neutral: + statusLabel.apply(style: .neutralStatusLabel) + } + } + + func bind(timeModel: Model.Time?) { + if let time = timeModel { + timeView.bind(viewModel: time.titleIcon) + timeView.apply(style: time.isUrgent ? .activeTimeView : .timeView) + } else { + timeView.bind(viewModel: nil) + } + } +} + +extension IconDetailsView.Style { + static let timeView = IconDetailsView.Style( + tintColor: R.color.colorWhite64()!, + font: .caption1 + ) + static let activeTimeView = IconDetailsView.Style( + tintColor: R.color.colorDarkYellow()!, + font: .caption1 + ) +} + +extension UILabel.Style { + static let positiveStatusLabel = UILabel.Style( + textColor: R.color.colorDarkGreen(), + font: .semiBoldCaps1 + ) + static let neutralStatusLabel = UILabel.Style( + textColor: R.color.colorWhite64(), + font: .semiBoldCaps1 + ) + static let negativeStatusLabel = UILabel.Style( + textColor: R.color.colorRedFF3A69(), + font: .semiBoldCaps1 + ) + static let title = UILabel.Style( + textColor: .white, + font: .regularSubheadline + ) + + static let track = UILabel.Style( + textColor: R.color.colorWhite64(), + font: .semiBoldCaps1 + ) +} + +extension RoundedView.Style { + static let referendum = RoundedView.Style( + fillColor: R.color.colorWhite8()!, + highlightedFillColor: R.color.colorWhite8()!, + cornerRadius: 8 + ) +} diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift b/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift new file mode 100644 index 0000000000..2a0d2166a1 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift @@ -0,0 +1,72 @@ +import UIKit + +final class ReferendumView: UIView { + let referendumInfoView = ReferendumInfoView() + let progressView = VotingProgressView() + let yourVoteView = YourVotesView() + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.vStack( + spacing: 0, + [ + referendumInfoView, + progressView, + yourVoteView + ] + ) + + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } +} + +typealias ReferendumTableViewCell = BlurredTableViewCell + +extension ReferendumTableViewCell { + func applyStyle() { + contentInsets = .init(top: 8, left: 16, bottom: 8, right: 16) + innerInsets = .init(top: 16, left: 16, bottom: 16, right: 16) + } +} + +extension ReferendumView { + struct Model { + let referendumInfo: ReferendumInfoView.Model + let progress: VotingProgressView.Model? + let yourVotes: YourVotesView.Model? + } + + func bind(viewModel: LoadableViewModelState) { + // TODO: Skeleton + guard let model = viewModel.value else { + return + } + referendumInfoView.bind(viewModel: model.referendumInfo) + if let progressModel = model.progress { + progressView.bind(viewModel: progressModel) + progressView.isHidden = false + } else { + progressView.isHidden = true + } + + if let yourVotesModel = model.yourVotes { + yourVoteView.bind(viewModel: yourVotesModel) + yourVoteView.isHidden = false + } else { + yourVoteView.isHidden = true + } + } +} diff --git a/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift b/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift new file mode 100644 index 0000000000..19829e4dab --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift @@ -0,0 +1,33 @@ +import UIKit + +extension SliderLayer.Style { + static let governance = SliderLayer.Style( + firstColor: UIColor(red: 0.081, green: 0.812, blue: 0.215, alpha: 1), + lastColor: UIColor(red: 0.749, green: 0.216, blue: 0.345, alpha: 1), + cornerRadius: 4, + dividerSpace: 6 + ) +} + +extension SegmentedSliderView.ThumbStyle { + static let governance = SegmentedSliderView.ThumbStyle( + color: .white, + cornerRadius: 8, + width: 3, + height: nil, + shadow: .init( + color: UIColor(red: 0, green: 0, blue: 0, alpha: 0.72), + opacity: 1, + offset: .zero, + radius: 8 + ) + ) +} + +extension SegmentedSliderView.Style { + static let governance = SegmentedSliderView.Style( + lineInsets: .init(top: 3, left: 0, bottom: 3, right: 0), + sliderStyle: .governance, + thumbStyle: .governance + ) +} diff --git a/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift b/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift new file mode 100644 index 0000000000..feb581f058 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift @@ -0,0 +1,129 @@ +import UIKit + +final class SegmentedSliderView: UIView { + private var style: Style = .defaultStyle + private var model: Model = .init() + + let slider = SliderLayer() + let thumb = ThumbLayer() + + override init(frame: CGRect) { + super.init(frame: frame) + + backgroundColor = .clear + + layer.addSublayer(slider) + layer.addSublayer(thumb) + + apply(style: style) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + let sliderFrame = bounds.inset(by: style.lineInsets) + slider.frame = sliderFrame + + guard let thumbValue = model.thumbValue, + let thumbStyle = style.thumbStyle else { + thumb.frame = .zero + return + } + + let thumbValueDouble = NSDecimalNumber(decimal: thumbValue).doubleValue + let originX = sliderFrame.size.width * thumbValueDouble - thumbStyle.width / 2 + let thumbHeight = thumbStyle.height ?? bounds.size.height + let originY = sliderFrame.midY - thumbHeight / 2 + let origin = CGPoint(x: originX, y: originY) + let size = CGSize(width: thumbStyle.width, height: thumbHeight) + thumb.frame = CGRect(origin: origin, size: size) + } + + override var intrinsicContentSize: CGSize { + CGSize(width: UIView.noIntrinsicMetric, height: 11) + } +} + +extension SegmentedSliderView { + typealias SliderStyle = SliderLayer.Style + struct Style { + let lineInsets: UIEdgeInsets + let sliderStyle: SliderStyle + let thumbStyle: ThumbStyle? + + static let defaultStyle = Style( + lineInsets: .init(top: 3, left: 0, bottom: 3, right: 0), + sliderStyle: .defaultStyle, + thumbStyle: .defaultStyle + ) + } + + struct ThumbStyle { + let color: UIColor + let cornerRadius: CGFloat + let width: CGFloat + let height: CGFloat? + var shadow: ShadowStyle + + static let defaultStyle = ThumbStyle( + color: .white, + cornerRadius: 8, + width: 3, + height: nil, + shadow: .defaultStyle + ) + } + + struct ShadowStyle { + let color: UIColor + let opacity: Float + let offset: CGSize + let radius: CGFloat + + static let defaultStyle = ShadowStyle( + color: UIColor(red: 0, green: 0, blue: 0, alpha: 0.72), + opacity: 1, + offset: .zero, + radius: 8 + ) + } + + func apply(style: Style) { + self.style = style + slider.apply(style: style.sliderStyle) + + style.thumbStyle.map { + thumb.apply(style: .init(color: $0.color, cornerRadius: $0.cornerRadius)) + thumb.shadowColor = $0.shadow.color.cgColor + thumb.shadowOpacity = $0.shadow.opacity + thumb.shadowOffset = $0.shadow.offset + thumb.shadowRadius = $0.shadow.radius + } + + setNeedsDisplay() + } +} + +extension SegmentedSliderView { + struct Model { + let thumbValue: Decimal? + let value: Decimal + + init(thumbValue: Decimal? = nil, value: Decimal = 0) { + self.thumbValue = thumbValue + self.value = value + } + } + + func bind(viewModel: Model) { + model = viewModel + slider.gap = NSDecimalNumber(decimal: model.value).doubleValue + + setNeedsDisplay() + } +} diff --git a/novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift b/novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift new file mode 100644 index 0000000000..541f7f8d6f --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift @@ -0,0 +1,90 @@ +import UIKit + +final class SliderLayer: CALayer { + private let firstSegment: CAShapeLayer + private let lastSegment: CAShapeLayer + private var sliderStyle: Style = .defaultStyle + + var gap: CGFloat = 0 { + didSet { + setNeedsLayout() + } + } + + override init(layer: Any) { + guard let other = layer as? SliderLayer else { + fatalError() + } + firstSegment = other.firstSegment + lastSegment = other.lastSegment + sliderStyle = other.sliderStyle + + super.init(layer: layer) + } + + override init() { + firstSegment = CAShapeLayer() + lastSegment = CAShapeLayer() + + super.init() + + addSublayer(firstSegment) + addSublayer(lastSegment) + + apply(style: sliderStyle) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSublayers() { + let lineCalculationSize = CGSize( + width: bounds.width - sliderStyle.dividerSpace, + height: bounds.height + ) + let firstSegmentSize = lineCalculationSize.applying(.init(scaleX: gap, y: 1)) + let lastSegmentSize = lineCalculationSize.applying(.init(scaleX: 1 - gap, y: 1)) + let space = firstSegmentSize.width + sliderStyle.dividerSpace + let lastSegmentOrigin = bounds.origin.applying(.init( + translationX: space, + y: 0 + )) + + let firstPath = UIBezierPath( + roundedRect: .init(origin: bounds.origin, size: firstSegmentSize), + cornerRadius: sliderStyle.cornerRadius + ) + let lastPath = UIBezierPath( + roundedRect: .init(origin: lastSegmentOrigin, size: lastSegmentSize), + cornerRadius: sliderStyle.cornerRadius + ) + + firstSegment.path = firstPath.cgPath + lastSegment.path = lastPath.cgPath + } +} + +extension SliderLayer { + struct Style { + let firstColor: UIColor + let lastColor: UIColor + let cornerRadius: CGFloat + let dividerSpace: CGFloat + + static let defaultStyle = Style( + firstColor: .green, + lastColor: .red, + cornerRadius: 4, + dividerSpace: 6 + ) + } + + func apply(style: Style) { + sliderStyle = style + firstSegment.fillColor = style.firstColor.cgColor + lastSegment.fillColor = style.lastColor.cgColor + setNeedsLayout() + } +} diff --git a/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift b/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift new file mode 100644 index 0000000000..739fe5a937 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift @@ -0,0 +1,54 @@ +import UIKit + +final class ThumbLayer: CALayer { + private var thumbStyle: Style = .defaultStyle + private let shapeLayer: CAShapeLayer + + override init() { + shapeLayer = .init() + + super.init() + + addSublayer(shapeLayer) + apply(style: thumbStyle) + } + + override init(layer: Any) { + guard let other = layer as? ThumbLayer else { + fatalError() + } + thumbStyle = other.thumbStyle + shapeLayer = other.shapeLayer + + super.init(layer: layer) + apply(style: thumbStyle) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSublayers() { + let thumbPath = UIBezierPath( + roundedRect: bounds, + cornerRadius: thumbStyle.cornerRadius + ) + shapeLayer.path = thumbPath.cgPath + } +} + +extension ThumbLayer { + struct Style { + let color: UIColor + let cornerRadius: CGFloat + + static let defaultStyle = Style(color: .gray, cornerRadius: 10) + } + + func apply(style: Style) { + thumbStyle = style + shapeLayer.fillColor = thumbStyle.color.cgColor + setNeedsLayout() + } +} diff --git a/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift new file mode 100644 index 0000000000..626add47d9 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift @@ -0,0 +1,54 @@ +import UIKit +import SoraUI + +extension UILabel { + struct Style { + let textColor: UIColor? + let font: UIFont + } + + convenience init(style: Style, textAlignment: NSTextAlignment = .left, numberOfLines: Int = 0) { + self.init() + self.textAlignment = textAlignment + self.numberOfLines = numberOfLines + apply(style: style) + } + + func apply(style: Style) { + textColor = style.textColor + font = style.font + } +} + +extension RoundedView { + struct Style { + let fillColor: UIColor + let highlightedFillColor: UIColor + let cornerRadius: CGFloat + } + + func apply(style: Style) { + fillColor = style.fillColor + highlightedFillColor = style.highlightedFillColor + cornerRadius = style.cornerRadius + } +} + +extension IconDetailsView { + struct Style { + let tintColor: UIColor + let font: UIFont + } + + func apply(style: Style) { + detailsLabel.apply(style: .init(textColor: style.tintColor, font: style.font)) + imageView.tintColor = style.tintColor + } +} + +extension IconDetailsView { + func bind(viewModel: TitleIconViewModel?) { + imageView.image = viewModel?.icon + detailsLabel.text = viewModel?.title + } +} diff --git a/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift new file mode 100644 index 0000000000..2fa3fceb55 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift @@ -0,0 +1,88 @@ +import UIKit + +final class VotingProgressView: UIView { + let thresholdView: IconDetailsView = .create { + $0.detailsLabel.apply(style: .referendaTimeView) + $0.imageView.contentMode = .scaleAspectFit + $0.iconWidth = 14 + $0.spacing = 5 + } + + let slider: SegmentedSliderView = .create { + $0.apply(style: .governance) + } + + let ayeProgressLabel: UILabel = .init(style: .referendaTimeView, textAlignment: .left) + let passProgressLabel: UILabel = .init(style: .referendaTimeView, textAlignment: .center) + let nayProgressLabel: UILabel = .init(style: .referendaTimeView, textAlignment: .right) + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.vStack( + spacing: 6, + [ + thresholdView, + slider, + UIView.hStack( + distribution: .fillEqually, + [ + ayeProgressLabel, + passProgressLabel, + nayProgressLabel + ] + ) + ] + ) + + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview().inset(UIEdgeInsets(top: 16, left: 0, bottom: 0, right: 0)) + } + } +} + +extension VotingProgressView { + struct Model { + let ayeProgress: String + let passProgress: String + let nayProgress: String + let thresholdModel: ThresholdModel? + let progress: Decimal + } + + struct ThresholdModel { + let titleIcon: TitleIconViewModel? + let value: Decimal + } + + func bind(viewModel: Model) { + slider.bind(viewModel: .init( + thumbValue: viewModel.thresholdModel?.value, + value: viewModel.progress + )) + + ayeProgressLabel.text = viewModel.ayeProgress + passProgressLabel.text = viewModel.passProgress + nayProgressLabel.text = viewModel.nayProgress + + thresholdView.bind(viewModel: viewModel.thresholdModel?.titleIcon) + thresholdView.isHidden = viewModel.thresholdModel?.titleIcon?.title == nil + } +} + +extension UILabel.Style { + static let referendaTimeView = UILabel.Style( + textColor: R.color.colorWhite64(), + font: .caption1 + ) +} diff --git a/novawallet/Modules/Vote/Governance/View/YourVoteView.swift b/novawallet/Modules/Vote/Governance/View/YourVoteView.swift new file mode 100644 index 0000000000..2783681bce --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/YourVoteView.swift @@ -0,0 +1,118 @@ +import UIKit + +final class YourVotesView: UIView { + let topLine = createSeparator(color: R.color.colorWhite8()) + let ayeView: YourVoteView = .create { + $0.typeView.titleLabel.apply(style: .ayeType) + } + + let nayView: YourVoteView = .create { + $0.typeView.titleLabel.apply(style: .nayType) + } + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.vStack( + spacing: 12, + [ + topLine, + ayeView, + nayView + ] + ) + + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview().inset(UIEdgeInsets(top: 13, left: 0, bottom: 0, right: 0)) + } + topLine.snp.makeConstraints { + $0.height.equalTo(1) + } + } +} + +extension YourVotesView { + struct Model { + let aye: YourVoteView.Model? + let nay: YourVoteView.Model? + } + + func bind(viewModel: Model) { + ayeView.isHidden = viewModel.aye == nil + ayeView.bind(viewModel: viewModel.aye) + nayView.isHidden = viewModel.nay == nil + nayView.bind(viewModel: viewModel.nay) + } +} + +final class YourVoteView: UIView { + let typeView: BorderedLabelView = .create { + $0.contentInsets = .init(top: 4, left: 8, bottom: 4, right: 8) + } + + let voteLabel = UILabel(style: .votes, textAlignment: .left) + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.hStack( + spacing: 6, + [ + typeView, + voteLabel + ] + ) + + voteLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } +} + +extension YourVoteView { + struct Model { + let title: String + let description: String + } + + func bind(viewModel: Model?) { + typeView.titleLabel.text = viewModel?.title + voteLabel.text = viewModel?.description + } +} + +extension UILabel.Style { + static let ayeType = UILabel.Style( + textColor: R.color.colorDarkGreen(), + font: .semiBoldCaps1 + ) + static let nayType = UILabel.Style( + textColor: R.color.colorRedFF3A69(), + font: .semiBoldCaps1 + ) + static let votes = UILabel.Style( + textColor: R.color.colorWhite64(), + font: .caption1 + ) +} diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanStatusSectionView.swift b/novawallet/Modules/Vote/Parent/View/VoteStatusSectionView.swift similarity index 94% rename from novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanStatusSectionView.swift rename to novawallet/Modules/Vote/Parent/View/VoteStatusSectionView.swift index f95b4975ae..84c5e62e5f 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanStatusSectionView.swift +++ b/novawallet/Modules/Vote/Parent/View/VoteStatusSectionView.swift @@ -1,7 +1,7 @@ import UIKit import SoraUI -final class CrowdloanStatusSectionView: UITableViewHeaderFooterView { +final class VoteStatusSectionView: UITableViewHeaderFooterView { var skeletonView: SkrullableView? private var viewModel: LoadableViewModelState? @@ -45,7 +45,7 @@ final class CrowdloanStatusSectionView: UITableViewHeaderFooterView { } } -extension CrowdloanStatusSectionView { +extension VoteStatusSectionView { struct Model { let title: String let count: Int @@ -64,7 +64,7 @@ extension CrowdloanStatusSectionView { } // swiftlint:disable nesting -extension CrowdloanStatusSectionView { +extension VoteStatusSectionView { private enum Constants { enum TitleLabelInsets { static let top: CGFloat = 24 @@ -81,7 +81,7 @@ extension CrowdloanStatusSectionView { // swiftlint:enable nesting -extension CrowdloanStatusSectionView: SkeletonableView { +extension VoteStatusSectionView: SkeletonableView { var skeletonSuperview: UIView { self } diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index f303ef56a9..47e51cd0ec 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -183,9 +183,18 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { let interactor = createGovernanceInteractor(for: state, wallet: wallet) let wireframe = ReferendumsWireframe() + let percentFormatter = NumberFormatter.percent + percentFormatter.roundingMode = .halfEven + let viewModelFactory = ReferendumsModelFactory( + assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), + percentFormatter: percentFormatter, + referendumNumberFormatter: .quantity + ) + let presenter = ReferendumsPresenter( interactor: interactor, wireframe: wireframe, + viewModelFactory: viewModelFactory, localizationManager: localizationManager, logger: logger ) diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 625bfb7900..5922a056f8 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -979,3 +979,25 @@ "wallet.account.locks.crowdloans" = "Crowdloans"; "tabbar.vote.title" = "Vote"; "tabbar.governance.title" = "Governance"; +"governance.referendums.status.preparing" = "preparing"; +"governance.referendums.status.preparing.inqueue" = "in queue"; +"governance.referendums.status.passing" = "passing"; +"governance.referendums.status.not.passing" = "not passing"; +"governance.referendums.status.approved" = "approved"; +"governance.referendums.status.rejected" = "rejected"; +"governance.referendums.status.cancelled" = "cancelled"; +"governance.referendums.status.timedOut" = "timed out"; +"governance.referendums.status.killed" = "killed"; +"governance.referendums.status.executed" = "executed"; + +"governance.referendums.time.deciding" = "Deciding in %@"; +"governance.referendums.time.timeout" = "Time out in %@"; +"governance.referendums.time.execute" = "Execute in %@"; +"governance.referendums.time.waiting.deposit" = "Waiting for deposit"; +"governance.referendums.time.approve" = "Approve in %@"; +"governance.referendums.time.reject" = "Reject in %@"; + +"governance.referendums.threshold" = "Threshold: %@ of %@"; +"governance.referendums.your.vote" = "Your vote: %@ votes"; +"governance.referendums.active" = "Ongoing"; +"governance.referendums.completed" = "Completed"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 9295d1004f..82c78b6268 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -979,3 +979,25 @@ "wallet.account.locks.crowdloans" = "Краудлоуны"; "tabbar.vote.title" = "Голосование"; "tabbar.governance.title" = "Референдумы"; +"governance.referendums.status.preparing" = "подготовка"; +"governance.referendums.status.preparing.inqueue" = "в очереди"; +"governance.referendums.status.passing" = "прошел"; +"governance.referendums.status.not.passing" = "не прошел"; +"governance.referendums.status.approved" = "одобрен"; +"governance.referendums.status.rejected" = "отклонен"; +"governance.referendums.status.cancelled" = "отменен"; +"governance.referendums.status.timedOut" = "просрочен"; +"governance.referendums.status.killed" = "отменен"; +"governance.referendums.status.executed" = "выполнен"; + +"governance.referendums.time.deciding" = "Решение через %@"; +"governance.referendums.time.timeout" = "Истечет через %@"; +"governance.referendums.time.execute" = "Исполнение через %@"; +"governance.referendums.time.waiting.deposit" = "Ожидание депозита"; +"governance.referendums.time.approve" = "Одобрение через %@"; +"governance.referendums.time.reject" = "Отмена через %@"; + +"governance.referendums.threshold" = "Порог: %@ из %@"; +"governance.referendums.your.vote" = "Ваше голосование: %@ голосов"; +"governance.referendums.active" = "Активные"; +"governance.referendums.completed" = "Завершённые"; From a94cc7c7a1b241f6f8b38f5e138e3b32df268f73 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 12 Oct 2022 18:57:36 +0500 Subject: [PATCH 032/229] fetch action details --- .../ReferendumDetailsInteractor.swift | 146 +++++++++++++++++- .../ReferendumDetailsProtocols.swift | 2 +- 2 files changed, 142 insertions(+), 6 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 512e235228..4e78652d69 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -2,10 +2,10 @@ import UIKit import SubstrateSdk import RobinHood -final class ReferendumDetailsInteractor { +final class ReferendumDetailsInteractor: AnyCancellableCleaning { weak var presenter: ReferendumDetailsInteractorOutputProtocol? - let referendum: ReferendumLocal + private(set) var referendum: ReferendumLocal let chain: ChainModel let actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol let connection: JSONRPCEngine @@ -15,10 +15,15 @@ final class ReferendumDetailsInteractor { let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol + let referendumsOperationFactory: ReferendumsOperationFactoryProtocol let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? private var blockNumberSubscription: AnyDataProvider? + private var referendumSubscription: CallbackStorageSubscription? + private var referendumCancellable: CancellableCall? + private var identitiesCancellable: CancellableCall? + private var actionDetailsCancellable: CancellableCall? init( referendum: ReferendumLocal, @@ -31,6 +36,7 @@ final class ReferendumDetailsInteractor { priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol, + referendumsOperationFactory: ReferendumsOperationFactoryProtocol, currencyManager: CurrencyManagerProtocol, operationQueue: OperationQueue ) { @@ -44,12 +50,62 @@ final class ReferendumDetailsInteractor { self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory self.blockTimeService = blockTimeService self.govMetadataLocalSubscriptionFactory = govMetadataLocalSubscriptionFactory + self.referendumsOperationFactory = referendumsOperationFactory self.operationQueue = operationQueue self.currencyManager = currencyManager } + deinit { + clear(cancellable: &referendumCancellable) + clear(cancellable: &identitiesCancellable) + clear(cancellable: &actionDetailsCancellable) + + referendumSubscription = nil + } + + private func provideReferendum(for referendumInfo: ReferendumInfo) { + clear(cancellable: &referendumCancellable) + + let wrapper = referendumsOperationFactory.fetchReferendumWrapper( + for: referendumInfo, + index: Referenda.ReferendumIndex(referendum.index), + connection: connection, + runtimeProvider: runtimeProvider + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.referendumCancellable else { + return + } + + self?.referendumCancellable = nil + + do { + let referendum = try wrapper.targetOperation.extractNoCancellableResultData() + self?.referendum = referendum + + self?.presenter?.didReceiveReferendum(referendum) + } catch { + self?.presenter?.didReceiveError(.referendumFailed(error)) + } + } + } + + referendumCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } + private func handleReferendumSubscription(result: Result) { - + switch result { + case let .success(referendumInfo): + if let referendumInfo = referendumInfo { + provideReferendum(for: referendumInfo) + } + case let .failure(error): + presenter?.didReceiveError(.referendumFailed(error)) + } } private func subscribeReferendum() { @@ -62,7 +118,7 @@ final class ReferendumDetailsInteractor { StringScaleMapper(value: referendumIndex) } - let subscription = CallbackStorageSubscription( + referendumSubscription = CallbackStorageSubscription( request: request, connection: connection, runtimeService: runtimeProvider, @@ -70,7 +126,79 @@ final class ReferendumDetailsInteractor { operationQueue: operationQueue, callbackQueue: .main ) { [weak self] result in + self?.handleReferendumSubscription(result: result) + } + } + private func provideIdentities() { + guard let proposer = referendum.proposer else { + presenter?.didReceiveIdentities([:]) + return + } + + guard identitiesCancellable == nil else { + return + } + + let accountIds: () throws -> [AccountId] = { + [proposer] + } + + let wrapper = identityOperationFactory.createIdentityWrapper( + for: accountIds, + engine: connection, + runtimeService: runtimeProvider, + chainFormat: chain.chainFormat + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.identitiesCancellable else { + return + } + + self?.identitiesCancellable = nil + + do { + let identities = try wrapper.targetOperation.extractNoCancellableResultData() + self?.presenter?.didReceiveIdentities(identities) + } catch { + self?.presenter?.didReceiveError(.identitiesFailed(error)) + } + } + } + + identitiesCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } + + private func provideActionDetails() { + guard actionDetailsCancellable == nil else { + return + } + + let wrapper = actionDetailsOperationFactory.fetchActionWrapper( + for: referendum, + connection: connection, + runtimeProvider: runtimeProvider + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.actionDetailsCancellable else { + return + } + + self?.actionDetailsCancellable = nil + + do { + let actionDetails = try wrapper.targetOperation.extractNoCancellableResultData() + self?.presenter?.didReceiveActionDetails(actionDetails) + } catch { + self?.presenter?.didReceiveError(.actionDetailsFailed(error)) + } + } } } @@ -80,12 +208,18 @@ final class ReferendumDetailsInteractor { } blockNumberSubscription = subscribeToBlockNumber(for: chain.chainId) + + subscribeReferendum() } } extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol { func setup() { + presenter?.didReceiveReferendum(referendum) + makeSubscriptions() + provideActionDetails() + provideIdentities() } } @@ -116,7 +250,9 @@ extension ReferendumDetailsInteractor: PriceLocalSubscriptionHandler, PriceLocal extension ReferendumDetailsInteractor: SelectedCurrencyDepending { func applyCurrency() { if presenter != nil { - subscribeToAssetPrice() + if let priceId = chain.utilityAsset()?.priceId { + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 41a99722b2..87ca6994fa 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -12,7 +12,7 @@ protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { func didReceiveReferendum(_ referendum: ReferendumLocal) func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) func didReceiveMetadata(_ referendumMetadata: ReferendumMetadataLocal?) - func didReceiveIdentities(_ identities: [AccountId: AccountIdentity]) + func didReceiveIdentities(_ identities: [AccountAddress: AccountIdentity]) func didReceivePrice(_ price: PriceData?) func didReceiveBlockNumber(_ blockNumber: BlockNumber) func didReceiveBlockTime(_ blockTime: BlockTime) From 15d6e47ef1bf23fb3fdf68f4c25757fd64bb6ff7 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 12 Oct 2022 23:19:41 +0500 Subject: [PATCH 033/229] add governance details interactor --- .../ChainBalanceViewModelFactory.swift | 6 +- .../ReferendumDetailsInteractor.swift | 67 ++++++++++++- .../ReferendumDetailsPresenter.swift | 99 ++++++++++++++++++- .../ReferendumDetailsProtocols.swift | 8 +- .../ReferendumDetailsViewFactory.swift | 15 ++- 5 files changed, 185 insertions(+), 10 deletions(-) diff --git a/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift b/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift index 1cc322f1f8..c53453b6d5 100644 --- a/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift +++ b/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift @@ -8,7 +8,11 @@ final class ChainBalanceViewModelFactory { self.formatterFactory = formatterFactory } - func createViewModel(from chainAsset: ChainAsset, balanceInPlank: BigUInt?, locale: Locale) -> ChainBalanceViewModel { + func createViewModel( + from chainAsset: ChainAsset, + balanceInPlank: BigUInt?, + locale: Locale + ) -> ChainBalanceViewModel { let name = chainAsset.chain.name let displayInfo = chainAsset.assetDisplayInfo diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 4e78652d69..1fd6262c7f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -19,11 +19,14 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? + private var metadataProvider: AnySingleValueProvider? private var blockNumberSubscription: AnyDataProvider? private var referendumSubscription: CallbackStorageSubscription? + private var referendumCancellable: CancellableCall? private var identitiesCancellable: CancellableCall? private var actionDetailsCancellable: CancellableCall? + private var blockTimeCancellable: CancellableCall? init( referendum: ReferendumLocal, @@ -59,6 +62,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { clear(cancellable: &referendumCancellable) clear(cancellable: &identitiesCancellable) clear(cancellable: &actionDetailsCancellable) + clear(cancellable: &blockTimeCancellable) referendumSubscription = nil } @@ -173,6 +177,35 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } + private func provideBlockTime() { + guard blockTimeCancellable == nil else { + return + } + + let operation = blockTimeService.createEstimatedBlockTimeOperation() + + operation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard operation === self?.blockTimeCancellable else { + return + } + + self?.blockTimeCancellable = nil + + do { + let blockTimeModel = try operation.extractNoCancellableResultData() + self?.presenter?.didReceiveBlockTime(blockTimeModel.blockTime) + } catch { + self?.presenter?.didReceiveError(.blockTimeFailed(error)) + } + } + } + + blockTimeCancellable = operation + + operationQueue.addOperation(operation) + } + private func provideActionDetails() { guard actionDetailsCancellable == nil else { return @@ -210,21 +243,37 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { blockNumberSubscription = subscribeToBlockNumber(for: chain.chainId) subscribeReferendum() + + metadataProvider = subscribeGovMetadata(for: chain) } } extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol { func setup() { - presenter?.didReceiveReferendum(referendum) - makeSubscriptions() provideActionDetails() provideIdentities() } + + func refreshBlockTime() { + provideBlockTime() + } + + func refreshActionDetails() { + provideActionDetails() + } + + func refreshIdentities() { + provideIdentities() + } + + func remakeSubscriptions() { + makeSubscriptions() + } } extension ReferendumDetailsInteractor: GeneralLocalStorageSubscriber, GeneralLocalStorageHandler { - func handleBlockNumber(result: Result, chainId: ChainModel.Id) { + func handleBlockNumber(result: Result, chainId _: ChainModel.Id) { switch result { case let .success(blockNumber): if let blockNumber = blockNumber { @@ -247,6 +296,18 @@ extension ReferendumDetailsInteractor: PriceLocalSubscriptionHandler, PriceLocal } } +extension ReferendumDetailsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataLocalStorageHandler { + func handleGovMetadata(result: Result, chain _: ChainModel) { + switch result { + case let .success(mapping): + let metadata = mapping?[Referenda.ReferendumIndex(referendum.index)] + presenter?.didReceiveMetadata(metadata) + case let .failure(error): + presenter?.didReceiveError(.metadataFailed(error)) + } + } +} + extension ReferendumDetailsInteractor: SelectedCurrencyDepending { func applyCurrency() { if presenter != nil { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 218561c55e..ec205b9705 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -1,21 +1,114 @@ import Foundation +import SoraFoundation final class ReferendumDetailsPresenter { weak var view: ReferendumDetailsViewProtocol? let wireframe: ReferendumDetailsWireframeProtocol let interactor: ReferendumDetailsInteractorInputProtocol + let chain: ChainModel + let logger: LoggerProtocol + + private var referendum: ReferendumLocal + private var actionDetails: ReferendumActionLocal? + private var referendumMetadata: ReferendumMetadataLocal? + private var identities: [AccountAddress: AccountIdentity]? + private var price: PriceData? + private var blockNumber: BlockNumber? + private var blockTime: BlockTime? + init( interactor: ReferendumDetailsInteractorInputProtocol, - wireframe: ReferendumDetailsWireframeProtocol + wireframe: ReferendumDetailsWireframeProtocol, + referendum: ReferendumLocal, + chain: ChainModel, + localizationManager: LocalizationManagerProtocol, + logger: LoggerProtocol ) { self.interactor = interactor self.wireframe = wireframe + self.referendum = referendum + self.chain = chain + self.logger = logger + self.localizationManager = localizationManager } } extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { - func setup() {} + func setup() { + interactor.setup() + } +} + +extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol { + func didReceiveReferendum(_ referendum: ReferendumLocal) { + self.referendum = referendum + + logger.info("Did receive referendum") + } + + func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) { + self.actionDetails = actionDetails + + logger.info("Did receive action details") + } + + func didReceiveMetadata(_ referendumMetadata: ReferendumMetadataLocal?) { + self.referendumMetadata = referendumMetadata + + logger.info("Did receive metadata") + } + + func didReceiveIdentities(_ identities: [AccountAddress: AccountIdentity]) { + self.identities = identities + + logger.info("Did receive identity") + } + + func didReceivePrice(_ price: PriceData?) { + self.price = price + + logger.info("Did receive price") + } + + func didReceiveBlockNumber(_ blockNumber: BlockNumber) { + self.blockNumber = blockNumber + + logger.info("Did receive block number") + } + + func didReceiveBlockTime(_ blockTime: BlockTime) { + self.blockTime = blockTime + + logger.info("Did receive block time") + } + + func didReceiveError(_ error: ReferendumDetailsInteractorError) { + logger.error("Did receive error: \(error)") + + switch error { + case .referendumFailed, .priceFailed, .blockNumberFailed, .metadataFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + case .actionDetailsFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refreshActionDetails() + } + case .identitiesFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refreshIdentities() + } + case .blockTimeFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refreshBlockTime() + } + } + } } -extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol {} +extension ReferendumDetailsPresenter: Localizable { + func applyLocalization() { + if let view = view, view.isSetup {} + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 87ca6994fa..7f396f4668 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -1,4 +1,4 @@ -protocol ReferendumDetailsViewProtocol: AnyObject {} +protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol {} protocol ReferendumDetailsPresenterProtocol: AnyObject { func setup() @@ -6,6 +6,10 @@ protocol ReferendumDetailsPresenterProtocol: AnyObject { protocol ReferendumDetailsInteractorInputProtocol: AnyObject { func setup() + func refreshBlockTime() + func refreshActionDetails() + func refreshIdentities() + func remakeSubscriptions() } protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { @@ -19,4 +23,4 @@ protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { func didReceiveError(_ error: ReferendumDetailsInteractorError) } -protocol ReferendumDetailsWireframeProtocol: AnyObject {} +protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index edf9f25090..569a0548db 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -1,6 +1,7 @@ import Foundation import SubstrateSdk import RobinHood +import SoraFoundation struct ReferendumDetailsViewFactory { static func createView( @@ -19,7 +20,16 @@ struct ReferendumDetailsViewFactory { let wireframe = ReferendumDetailsWireframe() - let presenter = ReferendumDetailsPresenter(interactor: interactor, wireframe: wireframe) + let localizationManager = LocalizationManager.shared + + let presenter = ReferendumDetailsPresenter( + interactor: interactor, + wireframe: wireframe, + referendum: referendum, + chain: state.settings.value, + localizationManager: localizationManager, + logger: Logger.shared + ) let view = ReferendumDetailsViewController(presenter: presenter) @@ -63,6 +73,8 @@ struct ReferendumDetailsViewFactory { emptyIdentitiesWhenNoStorage: true ) + let referendumsOperationFactory = Gov2OperationFactory(requestFactory: requestFactory) + return ReferendumDetailsInteractor( referendum: referendum, chain: chain, @@ -74,6 +86,7 @@ struct ReferendumDetailsViewFactory { priceLocalSubscriptionFactory: PriceProviderFactory.shared, generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, govMetadataLocalSubscriptionFactory: state.govMetadataLocalSubscriptionFactory, + referendumsOperationFactory: referendumsOperationFactory, currencyManager: currencyManager, operationQueue: OperationManagerFacade.sharedDefaultQueue ) From 40724e4ff0a61f3c8650e2740ccba484f7a0729d Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 12 Oct 2022 23:25:38 +0400 Subject: [PATCH 034/229] added statusview --- novawallet.xcodeproj/project.pbxproj | 16 +++ .../ReferendumVotingStatusDetailsView.swift | 44 ++++++++ .../View/ReferendumVotingStatusView.swift | 102 ++++++++++++++++++ .../Governance/View/ReferendumInfoView.swift | 2 +- 4 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index c845fea219..5e7e41877a 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2215,6 +2215,8 @@ 8887813C28B62B0A00E7290F /* FlexibleSpaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8887813B28B62B0A00E7290F /* FlexibleSpaceView.swift */; }; 8887813E28B7AA3100E7290F /* RoundedIconTitleCollectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8887813D28B7AA3100E7290F /* RoundedIconTitleCollectionHeaderView.swift */; }; 8887814028B7AAB700E7290F /* RoundedIconTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8887813F28B7AAB700E7290F /* RoundedIconTitleView.swift */; }; + 888A3B6528F73DC300E15BD2 /* ReferendumVotingStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 888A3B6428F73DC300E15BD2 /* ReferendumVotingStatusView.swift */; }; + 888A3B6728F746D200E15BD2 /* ReferendumVotingStatusDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 888A3B6628F746D200E15BD2 /* ReferendumVotingStatusDetailsView.swift */; }; 888B853828ED966600AC9614 /* SkeletonableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 888B853728ED966600AC9614 /* SkeletonableView.swift */; }; 8890E51628DDC98C001D3994 /* SubstrateStorageMigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8890E51528DDC98C001D3994 /* SubstrateStorageMigrationTests.swift */; }; 8892284828F353A5003F8B9E /* ReferendumsModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8892284728F353A5003F8B9E /* ReferendumsModelFactory.swift */; }; @@ -5050,6 +5052,8 @@ 8887813B28B62B0A00E7290F /* FlexibleSpaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlexibleSpaceView.swift; sourceTree = ""; }; 8887813D28B7AA3100E7290F /* RoundedIconTitleCollectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedIconTitleCollectionHeaderView.swift; sourceTree = ""; }; 8887813F28B7AAB700E7290F /* RoundedIconTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedIconTitleView.swift; sourceTree = ""; }; + 888A3B6428F73DC300E15BD2 /* ReferendumVotingStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotingStatusView.swift; sourceTree = ""; }; + 888A3B6628F746D200E15BD2 /* ReferendumVotingStatusDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotingStatusDetailsView.swift; sourceTree = ""; }; 888B853728ED966600AC9614 /* SkeletonableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SkeletonableView.swift; sourceTree = ""; }; 8890E51528DDC98C001D3994 /* SubstrateStorageMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubstrateStorageMigrationTests.swift; sourceTree = ""; }; 8892284728F353A5003F8B9E /* ReferendumsModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsModelFactory.swift; sourceTree = ""; }; @@ -11902,6 +11906,15 @@ path = View; sourceTree = ""; }; + 888A3B6328F73B9200E15BD2 /* View */ = { + isa = PBXGroup; + children = ( + 888A3B6428F73DC300E15BD2 /* ReferendumVotingStatusView.swift */, + 888A3B6628F746D200E15BD2 /* ReferendumVotingStatusDetailsView.swift */, + ); + path = View; + sourceTree = ""; + }; 88A0E0FB28A284C700A9C940 /* Currency */ = { isa = PBXGroup; children = ( @@ -12589,6 +12602,7 @@ B4F0332763AFF64A3793C679 /* ReferendumDetails */ = { isa = PBXGroup; children = ( + 888A3B6328F73B9200E15BD2 /* View */, C3ABAD23C0039AFA8351C650 /* ReferendumDetailsProtocols.swift */, 5E2EB9EE4A87BD4A74040784 /* ReferendumDetailsWireframe.swift */, 78536852751EF56F58C5691E /* ReferendumDetailsPresenter.swift */, @@ -13998,6 +14012,7 @@ 84DD5F77263DFD9C00425ACF /* WarningConditionViolation.swift in Sources */, 84D2F45425EF044B008B914D /* RecommendedValidatorListViewModel.swift in Sources */, 84FD3DB52540ED0900A234E3 /* Block.swift in Sources */, + 888A3B6728F746D200E15BD2 /* ReferendumVotingStatusDetailsView.swift in Sources */, 8494D86B25247F9600614D8F /* Decimal+String.swift in Sources */, 849E17F2279191EB002D1744 /* DAppSettingsMapper.swift in Sources */, 84873B0926029CBD000A83EE /* StakingStateViewModelFactory.swift in Sources */, @@ -14210,6 +14225,7 @@ F471897626C297AA006487AD /* AnalyticsValidatorsPage.swift in Sources */, F44CD8F426242825005DDF23 /* PayoutRewardsService+Fetch.swift in Sources */, 2AD0A19525D3D3EC00312428 /* GitHubOperationFactory.swift in Sources */, + 888A3B6528F73DC300E15BD2 /* ReferendumVotingStatusView.swift in Sources */, 843E9B3627C8B915009C143A /* NftFileDownloadService.swift in Sources */, 842B17FF28649CCD0014CC57 /* CrossChainDestinationSelectionState.swift in Sources */, 84A3034926A834F900E64382 /* ValidatorInfoViewLayout.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift new file mode 100644 index 0000000000..266a1c561e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -0,0 +1,44 @@ +import UIKit + +final class ReferendumVotingStatusDetailsView: UIView { + let statusView = ReferendumVotingStatusView() + let votingProgressView = VotingProgressView() + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.vStack( + spacing: 16, + [ + statusView, + votingProgressView + ] + ) + + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } +} + +extension ReferendumVotingStatusDetailsView { + struct Model { + let status: ReferendumVotingStatusView.Model + let votingProgress: VotingProgressView.Model + } + + func bind(viewModel: Model) { + statusView.bind(viewModel: viewModel.status) + votingProgressView.bind(viewModel: viewModel.votingProgress) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift new file mode 100644 index 0000000000..8e1d384d98 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift @@ -0,0 +1,102 @@ +import UIKit + +final class ReferendumVotingStatusView: UIView { + let titleLabel: UILabel = .init(style: .title) + let statusLabel: UILabel = .init(style: .positiveStatusLabel) + + let timeView: IconDetailsView = .create { + $0.mode = .detailsIcon + $0.detailsLabel.numberOfLines = 1 + $0.spacing = 5 + $0.apply(style: .timeView) + } + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.vStack( + spacing: 8, + [ + UIView.hStack([ + statusLabel, + UIView(), + timeView + ]), + titleLabel + ] + ) + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } +} + +extension ReferendumVotingStatusView { + struct Model { + let status: Status + let time: Time? + let title: String? + } + + struct Time: Equatable { + let titleIcon: TitleIconViewModel + let isUrgent: Bool + } + + struct Status { + let name: String + let kind: StatusKind + } + + enum StatusKind { + case positive + case neutral + } + + func bind(viewModel: Model) { + titleLabel.text = viewModel.title + statusLabel.text = viewModel.status.name + bind(timeModel: viewModel.time) + + switch viewModel.status.kind { + case .positive: + statusLabel.apply(style: .positiveStatusLabel) + case .neutral: + statusLabel.apply(style: .neutralStatusLabel) + } + } + + func bind(timeModel: Model.Time?) { + if let time = timeModel { + timeView.bind(viewModel: time.titleIcon) + timeView.apply(style: time.isUrgent ? .activeTimeView : .timeView) + } else { + timeView.bind(viewModel: nil) + } + } + +} +private extension UILabel.Style { + static let positiveStatusLabel = UILabel.Style( + textColor: R.color.colorDarkGreen(), + font: .boldTitle2 + ) + static let negativeStatusLabel = UILabel.Style( + textColor: R.color.colorRedFF3A69(), + font: .boldTitle2 + ) + static let title = UILabel.Style( + textColor: R.color.colorWhite64()!, + font: .regularFootnote + ) +} diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift index b4e4561881..d9aee83b6e 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -139,7 +139,7 @@ extension IconDetailsView.Style { ) } -extension UILabel.Style { +private extension UILabel.Style { static let positiveStatusLabel = UILabel.Style( textColor: R.color.colorDarkGreen(), font: .semiBoldCaps1 From b691a4d1a264e88d478645ab5aa167c0159cddee Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 13 Oct 2022 12:49:55 +0500 Subject: [PATCH 035/229] fix referendums list --- novawallet.xcodeproj/project.pbxproj | 24 +- .../colorBlack72.colorset/Contents.json | 20 + .../Contents.json | 0 .../Governance/Model/ReferendumLocal.swift | 19 +- .../Model/ReferendumsModelFactory.swift | 570 ------------------ .../Referendums/ReferendumsPresenter.swift | 17 +- .../Referendums/ReferendumsProtocols.swift | 2 +- .../Referendums/ReferendumsViewManager.swift | 2 +- .../Governance/View/ReferendumInfoView.swift | 2 +- .../View/Slider/GovernanceStyle.swift | 7 +- .../View/Slider/SegmentedSliderView.swift | 20 +- .../Governance/View/Slider/SliderLayer.swift | 82 ++- .../Governance/View/Slider/ThumbLayer.swift | 3 + .../Governance/View/VotingProgressView.swift | 30 +- .../Vote/Governance/View/YourVoteView.swift | 2 +- .../ReferendumStatusViewModelFactory.swift | 184 ++++++ .../ViewModel/ReferendumsModelFactory.swift | 414 +++++++++++++ .../ReferendumsViewModel.swift | 0 .../StatusTimeViewModel.swift} | 2 +- .../Parent/VoteChildPresenterFactory.swift | 9 +- novawallet/en.lproj/Localizable.strings | 5 + novawallet/ru.lproj/Localizable.strings | 6 + 22 files changed, 771 insertions(+), 649 deletions(-) create mode 100644 novawallet/Assets.xcassets/colorBlack72.colorset/Contents.json rename novawallet/Assets.xcassets/{colorDarkGreen.colorset => colorGreen15CF37.colorset}/Contents.json (100%) delete mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumsModelFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift rename novawallet/Modules/Vote/Governance/{Model => ViewModel}/ReferendumsViewModel.swift (100%) rename novawallet/Modules/Vote/Governance/{Model/StatusTimeModel.swift => ViewModel/StatusTimeViewModel.swift} (86%) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index c845fea219..bdc49d62ed 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -892,6 +892,7 @@ 8454C2832632FC2500657DAD /* ExtrinsicProcessingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8454C2822632FC2500657DAD /* ExtrinsicProcessingTests.swift */; }; 845532D02684690D00C2645D /* ParachainSlotLease.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845532CF2684690D00C2645D /* ParachainSlotLease.swift */; }; 845532D226846B6800C2645D /* ParachainLeaseInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845532D126846B6800C2645D /* ParachainLeaseInfo.swift */; }; + 8455AB4528F7F05400974E88 /* ReferendumStatusViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8455AB4428F7F05400974E88 /* ReferendumStatusViewModelFactory.swift */; }; 84563D0924F46B7F0055591D /* ManagedAccountItemMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84563D0824F46B7F0055591D /* ManagedAccountItemMapperTests.swift */; }; 8456C08227CF9DC9001282DE /* RemoteNftModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8456C08127CF9DC9001282DE /* RemoteNftModel.swift */; }; 8456C08427CFA4A7001282DE /* ImagePlaceholderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8456C08327CFA4A7001282DE /* ImagePlaceholderView.swift */; }; @@ -2236,7 +2237,7 @@ 88AC186528CA461F00892A9B /* ModalSheetCollectionViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AC186428CA461F00892A9B /* ModalSheetCollectionViewProtocol.swift */; }; 88AF35DE28C21D28003730DA /* LocksSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AF35DD28C21D28003730DA /* LocksSubscription.swift */; }; 88B1862A28EF30A600D49854 /* YourVoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B1862928EF30A600D49854 /* YourVoteView.swift */; }; - 88B438E728F6C629001FC08A /* StatusTimeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B438E628F6C629001FC08A /* StatusTimeModel.swift */; }; + 88B438E728F6C629001FC08A /* StatusTimeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B438E628F6C629001FC08A /* StatusTimeViewModel.swift */; }; 88BB21A028D34C660019C6B4 /* DataProviderChange+Identifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88BB219F28D34C660019C6B4 /* DataProviderChange+Identifier.swift */; }; 88C017E628C60A65003B2D28 /* AssetLockMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C017E528C60A65003B2D28 /* AssetLockMapper.swift */; }; 88C7165428C894510015D1E9 /* CollectionViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C7165328C894510015D1E9 /* CollectionViewDelegate.swift */; }; @@ -3715,6 +3716,7 @@ 8454C2822632FC2500657DAD /* ExtrinsicProcessingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicProcessingTests.swift; sourceTree = ""; }; 845532CF2684690D00C2645D /* ParachainSlotLease.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParachainSlotLease.swift; sourceTree = ""; }; 845532D126846B6800C2645D /* ParachainLeaseInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParachainLeaseInfo.swift; sourceTree = ""; }; + 8455AB4428F7F05400974E88 /* ReferendumStatusViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumStatusViewModelFactory.swift; sourceTree = ""; }; 84563D0824F46B7F0055591D /* ManagedAccountItemMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedAccountItemMapperTests.swift; sourceTree = ""; }; 8456C08127CF9DC9001282DE /* RemoteNftModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteNftModel.swift; sourceTree = ""; }; 8456C08327CFA4A7001282DE /* ImagePlaceholderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePlaceholderView.swift; sourceTree = ""; }; @@ -5072,7 +5074,7 @@ 88AC186428CA461F00892A9B /* ModalSheetCollectionViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalSheetCollectionViewProtocol.swift; sourceTree = ""; }; 88AF35DD28C21D28003730DA /* LocksSubscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksSubscription.swift; sourceTree = ""; }; 88B1862928EF30A600D49854 /* YourVoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourVoteView.swift; sourceTree = ""; }; - 88B438E628F6C629001FC08A /* StatusTimeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTimeModel.swift; sourceTree = ""; }; + 88B438E628F6C629001FC08A /* StatusTimeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTimeViewModel.swift; sourceTree = ""; }; 88BB219F28D34C660019C6B4 /* DataProviderChange+Identifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataProviderChange+Identifier.swift"; sourceTree = ""; }; 88C017E528C60A65003B2D28 /* AssetLockMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetLockMapper.swift; sourceTree = ""; }; 88C7165328C894510015D1E9 /* CollectionViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewDelegate.swift; sourceTree = ""; }; @@ -7699,6 +7701,17 @@ path = ViewModel; sourceTree = ""; }; + 8455AB4628F7F07200974E88 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 8892284728F353A5003F8B9E /* ReferendumsModelFactory.swift */, + 8892284928F35410003F8B9E /* ReferendumsViewModel.swift */, + 88B438E628F6C629001FC08A /* StatusTimeViewModel.swift */, + 8455AB4428F7F05400974E88 /* ReferendumStatusViewModelFactory.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; 8457F91126EB9088006803E1 /* EntityToModel */ = { isa = PBXGroup; children = ( @@ -8362,6 +8375,7 @@ 847A25C028D84A3D006AC9F5 /* Governance */ = { isa = PBXGroup; children = ( + 8455AB4628F7F07200974E88 /* ViewModel */, 880059D628EEA55500E87B9B /* View */, 84A1742528ED60610096F943 /* Operation */, 84D8753B28EB1796004065BD /* Model */, @@ -11102,13 +11116,10 @@ 84A1742328ED3CF70096F943 /* ReferendumLocal.swift */, 84DD49F528EE974B00B804F3 /* ReferendumDecidingFunctionProtocol.swift */, 84E9A04F28F000AB00551DC4 /* ReferendumMetadataLocal.swift */, - 8892284728F353A5003F8B9E /* ReferendumsModelFactory.swift */, - 8892284928F35410003F8B9E /* ReferendumsViewModel.swift */, 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */, 841221A528F13BA100715C82 /* GovernanceServiceFactory.swift */, 849707A028F3E0AC00DD0A02 /* ReferendumVoterLocal.swift */, 845B811C28F44A700040CE84 /* ReferendumActionLocal.swift */, - 88B438E628F6C629001FC08A /* StatusTimeModel.swift */, ); path = Model; sourceTree = ""; @@ -14955,6 +14966,7 @@ 8448221826B1624E007F4492 /* SelectValidatorsConfirmViewLayout.swift in Sources */, 8490145624A9404E008F705E /* AttributedStringDecorator.swift in Sources */, D9046DBC27453D5C00C29F2E /* ParallelContributionResponse.swift in Sources */, + 8455AB4528F7F05400974E88 /* ReferendumStatusViewModelFactory.swift in Sources */, 8499FED227BFA39300712589 /* DataChangesDiffCalculator.swift in Sources */, 887AFC8C28BCB314002A0422 /* PolkadotIconDetailsView.swift in Sources */, 84CEAAF526D7ADF20021B881 /* KeystoreMigrator.swift in Sources */, @@ -16321,7 +16333,7 @@ 28B4C94DBAF461CBF18B1B63 /* WalletsListViewController.swift in Sources */, 233CB11F486DE1953D977295 /* WalletsListViewLayout.swift in Sources */, FD43B68CFBD5C3497B446F53 /* ChangeWatchOnlyProtocols.swift in Sources */, - 88B438E728F6C629001FC08A /* StatusTimeModel.swift in Sources */, + 88B438E728F6C629001FC08A /* StatusTimeViewModel.swift in Sources */, E65FDA8BF9DBE7F50AE9D733 /* ChangeWatchOnlyWireframe.swift in Sources */, 02838B00DD7C9BC3BD78FF65 /* ChangeWatchOnlyPresenter.swift in Sources */, 493A9637BE5A1BF4B0744A4C /* ChangeWatchOnlyInteractor.swift in Sources */, diff --git a/novawallet/Assets.xcassets/colorBlack72.colorset/Contents.json b/novawallet/Assets.xcassets/colorBlack72.colorset/Contents.json new file mode 100644 index 0000000000..ec4360ef43 --- /dev/null +++ b/novawallet/Assets.xcassets/colorBlack72.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.720", + "blue" : "0.000", + "green" : "0.000", + "red" : "0.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/colorDarkGreen.colorset/Contents.json b/novawallet/Assets.xcassets/colorGreen15CF37.colorset/Contents.json similarity index 100% rename from novawallet/Assets.xcassets/colorDarkGreen.colorset/Contents.json rename to novawallet/Assets.xcassets/colorGreen15CF37.colorset/Contents.json diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 0c2c9d82f7..0a227fa378 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -15,11 +15,11 @@ struct SupportAndVotesLocal { let totalIssuance: BigUInt /// fraction of ayes - var approvalFraction: Decimal { + var approvalFraction: Decimal? { guard let total = Decimal(ayes + nays), total > 0, let ayesDecimal = Decimal(ayes) else { - return 0.0 + return nil } return ayesDecimal / total @@ -43,7 +43,8 @@ struct SupportAndVotesLocal { func isPassing(at block: BlockNumber) -> Bool { guard let approvalThreshold = approvalFunction?.calculateThreshold(for: block), - let supportThreshold = supportFunction?.calculateThreshold(for: block) else { + let supportThreshold = supportFunction?.calculateThreshold(for: block), + let approvalFraction = approvalFraction else { return false } @@ -63,6 +64,10 @@ enum ReferendumStateLocal { let since: BlockNumber let period: Moment let confirmationUntil: BlockNumber? + + var rejectedAt: BlockNumber { + since + period + } } struct Preparing { @@ -74,6 +79,14 @@ enum ReferendumStateLocal { let preparingPeriod: Moment let timeoutPeriod: Moment let inQueue: Bool + + var preparingEnd: BlockNumber { + since + preparingPeriod + } + + var timeoutAt: BlockNumber { + since + timeoutPeriod + } } struct Approved { diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumsModelFactory.swift deleted file mode 100644 index af988fe990..0000000000 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumsModelFactory.swift +++ /dev/null @@ -1,570 +0,0 @@ -import Foundation -import SoraFoundation -import BigInt - -struct ReferendumsModelFactoryInput { - let referendums: [ReferendumLocal] - let metadataMapping: [Referenda.ReferendumIndex: ReferendumMetadataLocal]? - let votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal] - let chainInfo: ChainInformation - let locale: Locale - - struct ChainInformation { - let chain: ChainModel - let currentBlock: BlockNumber - let blockDurartion: UInt64 - } -} - -protocol ReferendumsModelFactoryProtocol { - func createSections(input: ReferendumsModelFactoryInput) -> [ReferendumsSection] - - func createTimeModels( - referendums: [ReferendumLocal], - currentBlock: BlockNumber, - blockDurartion: UInt64, - locale: Locale - ) -> [UInt: StatusTimeModel?] -} - -final class ReferendumsModelFactory { - private typealias Input = ReferendumsModelFactoryInput - private typealias Strings = R.string.localizable - - let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol - let percentFormatter: NumberFormatter - let referendumNumberFormatter: NumberFormatter - init( - assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, - percentFormatter: NumberFormatter, - referendumNumberFormatter: NumberFormatter - ) { - self.assetBalanceFormatterFactory = assetBalanceFormatterFactory - self.percentFormatter = percentFormatter - self.referendumNumberFormatter = referendumNumberFormatter - } - - private func provideCommonReferendumCellViewModel( - status: ReferendumInfoView.Model.Status, - metadata: ReferendumMetadataLocal?, - votes: ReferendumAccountVoteLocal?, - chain: ChainModel, - locale: Locale - ) -> ReferendumView.Model { - let yourVotesModel = createVotesViewModel( - votes: votes, - chainAsset: chain.utilityAsset(), - locale: locale - ) - return .init( - referendumInfo: .init( - status: status, - time: nil, - title: metadata?.name ?? "", - track: nil - ), - progress: nil, - yourVotes: yourVotesModel - ) - } - - private func providePreparingReferendumCellViewModel( - _ model: ReferendumStateLocal.Preparing, - referendum: ReferendumLocal, - metadata: ReferendumMetadataLocal?, - votes: ReferendumAccountVoteLocal?, - chainInfo: Input.ChainInformation, - locale: Locale - ) -> ReferendumView.Model { - let timeModel = createTimeModel( - for: referendum, - currentBlock: chainInfo.currentBlock, - blockDurartion: chainInfo.blockDurartion, - locale: locale - ) - - let title = model.inQueue ? - Strings.governanceReferendumsStatusPreparingInqueue(preferredLanguages: locale.rLanguages) : - Strings.governanceReferendumsStatusPreparing(preferredLanguages: locale.rLanguages) - - switch model.voting { - case let .supportAndVotes(supportAndVotes): - let progressViewModel = createVotingProgressViewModel( - supportAndVotes: supportAndVotes, - chain: chainInfo.chain, - currentBlock: chainInfo.currentBlock, - locale: locale - ) - let yourVotesModel = createVotesViewModel( - votes: votes, - chainAsset: chainInfo.chain.utilityAsset(), - locale: locale - ) - let trackName = model.track.name.replacingSnakeCase().uppercased() - let referendumNumber = referendumNumberFormatter.string(from: NSNumber(value: referendum.index)) - - return .init( - referendumInfo: .init( - status: .init(name: title.uppercased(), kind: .neutral), - time: timeModel?.viewModel, - title: metadata?.name ?? "", - track: .init( - titleIcon: .init(title: trackName, icon: nil), - referendumNumber: referendumNumber.map { "#" + $0 } - ) - ), - progress: progressViewModel, - yourVotes: yourVotesModel - ) - } - } - - private func createVotesViewModel( - votes: ReferendumAccountVoteLocal?, - chainAsset: AssetModel?, - locale: Locale - ) -> YourVotesView.Model? { - guard let votes = votes, - let chainAsset = chainAsset, - votes.ayes + votes.nays > 0 else { - return nil - } - - let inputFormatter = assetBalanceFormatterFactory.createInputFormatter(for: chainAsset.displayInfo) - - let formatVotes: (BigUInt) -> String = { votesInPlank in - guard let votes = Decimal.fromSubstrateAmount( - votesInPlank, - precision: Int16(chainAsset.precision) - ) else { - return "" - } - let votesString = inputFormatter.value(for: locale).stringFromDecimal(votes) ?? "" - return Strings.governanceReferendumsYourVote( - votesString, - preferredLanguages: locale.rLanguages - ) - } - let ayesModel = votes.ayes > 0 ? YourVoteView.Model( - title: "AYE", - description: formatVotes(votes.ayes) - ) : nil - let naysModel = votes.nays > 0 ? YourVoteView.Model( - title: "NAY", - description: formatVotes(votes.nays) - ) : nil - return .init( - aye: ayesModel, - nay: naysModel - ) - } - - private func provideDecidingReferendumCellViewModel( - _ model: ReferendumStateLocal.Deciding, - referendum: ReferendumLocal, - metadata: ReferendumMetadataLocal?, - chainInfo: Input.ChainInformation, - votes: ReferendumAccountVoteLocal?, - locale: Locale - ) -> ReferendumView.Model { - switch model.voting { - case let .supportAndVotes(supportAndVotes): - let timeModel: StatusTimeModel? - if supportAndVotes.isPassing(at: chainInfo.currentBlock), - let confirmationUntil = model.confirmationUntil { - timeModel = createTimeModel( - state: referendum.state, - atBlock: confirmationUntil, - currentBlock: chainInfo.currentBlock, - blockDuration: chainInfo.blockDurartion, - timeStringProvider: Strings.governanceReferendumsTimeApprove, - locale: locale - ) - } else { - timeModel = createTimeModel( - state: referendum.state, - atBlock: model.period, - currentBlock: chainInfo.currentBlock, - blockDuration: chainInfo.blockDurartion, - timeStringProvider: Strings.governanceReferendumsTimeReject, - locale: locale - ) - } - - let progressViewModel = createVotingProgressViewModel( - supportAndVotes: supportAndVotes, - chain: chainInfo.chain, - currentBlock: chainInfo.currentBlock, - locale: locale - ) - let isPassing = supportAndVotes.isPassing(at: chainInfo.currentBlock) - let statusName = isPassing ? - Strings.governanceReferendumsStatusPassing(preferredLanguages: locale.rLanguages) : - Strings.governanceReferendumsStatusNotPassing(preferredLanguages: locale.rLanguages) - let statusKind: ReferendumInfoView.Model.StatusKind = isPassing ? .positive : .negative - let yourVotesModel = createVotesViewModel( - votes: votes, - chainAsset: chainInfo.chain.utilityAsset(), - locale: locale - ) - let trackName = model.track.name.replacingSnakeCase().uppercased() - let referendumNumber = referendumNumberFormatter.string(from: NSNumber(value: referendum.index)) - - return .init( - referendumInfo: .init( - status: .init(name: statusName.uppercased(), kind: statusKind), - time: timeModel?.viewModel, - title: metadata?.name, - track: .init( - titleIcon: .init(title: trackName, icon: nil), - referendumNumber: referendumNumber.map { "#" + $0 } - ) - ), - progress: progressViewModel, - yourVotes: yourVotesModel - ) - } - } - - private func provideApprovedReferendumCellViewModel( - _ model: ReferendumStateLocal.Approved, - referendum: ReferendumLocal, - metadata: ReferendumMetadataLocal?, - chainInfo: Input.ChainInformation, - votes: ReferendumAccountVoteLocal?, - locale: Locale - ) -> ReferendumView.Model { - let timeModel: StatusTimeModel? - if let whenEnactment = model.whenEnactment { - timeModel = createTimeModel( - state: referendum.state, - atBlock: whenEnactment, - currentBlock: chainInfo.currentBlock, - blockDuration: chainInfo.blockDurartion, - timeStringProvider: Strings.governanceReferendumsTimeExecute, - locale: locale - ) - } else { - timeModel = nil - } - - let title = Strings.governanceReferendumsStatusApproved(preferredLanguages: locale.rLanguages) - let yourVotesModel = createVotesViewModel( - votes: votes, - chainAsset: chainInfo.chain.utilityAsset(), - locale: locale - ) - return .init( - referendumInfo: .init( - status: .init(name: title.uppercased(), kind: .positive), - time: timeModel?.viewModel, - title: metadata?.name, - track: nil - ), - progress: nil, - yourVotes: yourVotesModel - ) - } - - private func createVotingProgressViewModel( - supportAndVotes: SupportAndVotesLocal, - chain: ChainModel, - currentBlock: BlockNumber, - locale: Locale - ) -> VotingProgressView.Model { - let ayeProgress = percentFormatter.stringFromDecimal(supportAndVotes.approvalFraction) ?? "" - let nayProgress = percentFormatter.stringFromDecimal(1 - supportAndVotes.approvalFraction) ?? "" - let passProgress = percentFormatter.stringFromDecimal(supportAndVotes.supportFraction) ?? "" - let thresholdModel: VotingProgressView.ThresholdModel? - if let chainAsset = chain.utilityAsset(), - let supportThreshold = supportAndVotes.supportFunction?.calculateThreshold(for: currentBlock) { - let targetThreshold = Decimal.fromSubstrateAmount( - supportAndVotes.totalIssuance, - precision: Int16(chainAsset.precision) - ) - let threshold = Decimal.fromSubstrateAmount( - supportAndVotes.support, - precision: Int16(chainAsset.precision) - ) - let isCompleted = supportAndVotes.supportFraction >= supportThreshold - - let image = isCompleted ? - R.image.iconCheckmark()?.withTintColor(R.color.colorDarkGreen()!) : - R.image.iconClose()?.withTintColor(R.color.colorRedFF3A69()!) - let tokenFormatter = assetBalanceFormatterFactory.createTokenFormatter(for: chainAsset.displayInfo) - - let targetThresholdString = targetThreshold.map { - tokenFormatter.value(for: locale).stringFromDecimal($0) ?? "" - } ?? "" - let thresholdString = threshold.map(String.init) ?? "" - let text = R.string.localizable.governanceReferendumsThreshold(thresholdString, targetThresholdString) - thresholdModel = .init( - titleIcon: .init(title: text, icon: image), - value: supportAndVotes.supportFraction - ) - } else { - thresholdModel = nil - } - - return .init( - ayeProgress: "Aye: \(ayeProgress)", - passProgress: "To pass: \(passProgress)", - nayProgress: "Nay: \(nayProgress)", - thresholdModel: thresholdModel, - progress: supportAndVotes.approvalFraction - ) - } - - private func createTimeModel( - for referendum: ReferendumLocal, - currentBlock: BlockNumber, - blockDurartion: UInt64, - locale: Locale - ) -> StatusTimeModel? { - let strings = R.string.localizable.self - switch referendum.state { - case let .preparing(model): - if model.deposit == nil { - let title = strings.governanceReferendumsTimeWaitingDeposit(preferredLanguages: locale.rLanguages) - let timeViewModel = ReferendumInfoView.Model.Time( - titleIcon: .init(title: title, icon: R.image.iconLightPending()), - isUrgent: false - ) - - return StatusTimeModel(viewModel: timeViewModel, timeInterval: nil) { _ in - timeViewModel - } - } else { - return createTimeModel( - state: referendum.state, - atBlock: model.since, - currentBlock: currentBlock, - blockDuration: blockDurartion, - timeStringProvider: strings.governanceReferendumsTimeDeciding, - locale: locale - ) - } - case let .deciding(model): - switch model.voting { - case let .supportAndVotes(supportAndVotes): - if supportAndVotes.isPassing(at: currentBlock), - let confirmationUntil = model.confirmationUntil { - return createTimeModel( - state: referendum.state, - atBlock: confirmationUntil, - currentBlock: currentBlock, - blockDuration: blockDurartion, - timeStringProvider: strings.governanceReferendumsTimeApprove, - locale: locale - ) - } else { - return createTimeModel( - state: referendum.state, - atBlock: model.period, - currentBlock: currentBlock, - blockDuration: blockDurartion, - timeStringProvider: strings.governanceReferendumsTimeReject, - locale: locale - ) - } - } - case let .approved(model): - guard let whenEnactment = model.whenEnactment else { - return nil - } - return createTimeModel( - state: referendum.state, - atBlock: whenEnactment, - currentBlock: currentBlock, - blockDuration: blockDurartion, - timeStringProvider: strings.governanceReferendumsTimeExecute, - locale: locale - ) - case .rejected, .cancelled, .timedOut, .killed, .executed: - return nil - } - } - - private func createTimeModel( - state: ReferendumStateLocal, - atBlock: Moment, - currentBlock: BlockNumber, - blockDuration: UInt64, - timeStringProvider: @escaping (String, [String]?) -> String, - locale: Locale - ) -> StatusTimeModel? { - let time = calculateTime( - block: atBlock, - currentBlock: currentBlock, - blockDuration: blockDuration - ) - guard let timeModel = createTimeModel( - time: time, - timeStringProvider: timeStringProvider, - state: state, - locale: locale - ) else { - return nil - } - return .init(viewModel: timeModel, timeInterval: time) { [weak self] in - self?.createTimeModel( - time: $0, - timeStringProvider: timeStringProvider, - state: state, - locale: locale - ) - } - } - - private func createTimeModel( - time: TimeInterval, - timeStringProvider: (String, [String]?) -> String, - state: ReferendumStateLocal, - locale: Locale - ) -> ReferendumInfoView.Model.Time? { - guard let localizedDaysHours = time.localizedDaysOrTime(for: locale) else { - return nil - } - let timeString = timeStringProvider(localizedDaysHours, locale.rLanguages) - let timeModel = isUrgent(state: state, time: time).map { isUrgent in - ReferendumInfoView.Model.Time( - titleIcon: .init( - title: timeString, - icon: isUrgent ? R.image.iconFire() : R.image.iconLightPending() - ), - isUrgent: isUrgent - ) - } - return timeModel - } - - private func calculateTime(block: Moment, currentBlock: BlockNumber, blockDuration: UInt64) -> TimeInterval { - currentBlock.secondsTo(block: block, blockDuration: blockDuration) - } - - private func isUrgent(state: ReferendumStateLocal, time: TimeInterval) -> Bool? { - switch state { - case .preparing: - return time.hoursFromSeconds <= 3 - case .deciding: - return time.daysFromSeconds < 1 - case .approved: - return time.daysFromSeconds < 1 - case .rejected: - return time.daysFromSeconds < 1 - case .cancelled, .timedOut, .killed, .executed: return nil - } - } -} - -extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { - func createTimeModels( - referendums: [ReferendumLocal], - currentBlock: BlockNumber, - blockDurartion: UInt64, - locale: Locale - ) -> [UInt: StatusTimeModel?] { - referendums.reduce(into: [UInt: StatusTimeModel?]()) { result, referendum in - result[referendum.index] = createTimeModel( - for: referendum, - currentBlock: currentBlock, - blockDurartion: blockDurartion, - locale: locale - ) - } - } - - func createSections(input: ReferendumsModelFactoryInput) -> [ReferendumsSection] { - var active: [ReferendumsCellViewModel] = [] - var completed: [ReferendumsCellViewModel] = [] - - input.referendums.forEach { referendum in - let index = Referenda.ReferendumIndex(referendum.index) - let metadata = input.metadataMapping?[index] - let model = createReferendumsCellViewModel( - referendum: referendum, - metadata: metadata, - chainInformation: input.chainInfo, - votes: input.votes[index], - locale: input.locale - ) - let viewModel = ReferendumsCellViewModel( - referendumIndex: referendum.index, - viewModel: .loaded(value: model) - ) - referendum.state.completed ? completed.append(viewModel) : active.append(viewModel) - } - var sections: [ReferendumsSection] = [] - if !active.isEmpty { - let title = Strings.governanceReferendumsActive(preferredLanguages: input.locale.rLanguages) - sections.append(.active(.loaded(value: title), active)) - } - if !completed.isEmpty { - let title = Strings.governanceReferendumsCompleted(preferredLanguages: input.locale.rLanguages) - sections.append(.completed(.loaded(value: title), completed)) - } - return sections - } - - private func createReferendumsCellViewModel( - referendum: ReferendumLocal, - metadata: ReferendumMetadataLocal?, - chainInformation: Input.ChainInformation, - votes: ReferendumAccountVoteLocal?, - locale: Locale - ) -> ReferendumView.Model { - let status: ReferendumInfoView.Model.Status - switch referendum.state { - case let .preparing(model): - return providePreparingReferendumCellViewModel( - model, - referendum: referendum, - metadata: metadata, - votes: votes, - chainInfo: chainInformation, - locale: locale - ) - case let .deciding(model): - return provideDecidingReferendumCellViewModel( - model, - referendum: referendum, - metadata: metadata, - chainInfo: chainInformation, - votes: votes, - locale: locale - ) - case let .approved(model): - return provideApprovedReferendumCellViewModel( - model, - referendum: referendum, - metadata: metadata, - chainInfo: chainInformation, - votes: votes, - locale: locale - ) - case .rejected: - let statusName = Strings.governanceReferendumsStatusRejected(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .negative) - case .cancelled: - let statusName = Strings.governanceReferendumsStatusCancelled(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .neutral) - case .timedOut: - let statusName = Strings.governanceReferendumsStatusTimedOut(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .neutral) - case .killed: - let statusName = Strings.governanceReferendumsStatusKilled(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .negative) - case .executed: - let statusName = Strings.governanceReferendumsStatusExecuted(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .positive) - } - - return provideCommonReferendumCellViewModel( - status: status, - metadata: metadata, - votes: votes, - chain: chainInformation.chain, - locale: locale - ) - } -} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 8f3ed3e368..6ec9176104 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -7,6 +7,8 @@ final class ReferendumsPresenter { let interactor: ReferendumsInteractorInputProtocol let wireframe: ReferendumsWireframeProtocol + let viewModelFactory: ReferendumsModelFactoryProtocol + let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol let logger: LoggerProtocol private var freeBalance: BigUInt? @@ -16,12 +18,11 @@ final class ReferendumsPresenter { private var referendumsMetadata: ReferendumMetadataMapping? private var votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]? private var blockNumber: BlockNumber? - private let viewModelFactory: ReferendumsModelFactoryProtocol private var blockTime: BlockTime? private var maxStatusTimeInterval: TimeInterval? private var countdownTimer: CountdownTimer? - private var timeModels: [UInt: StatusTimeModel?]? + private var timeModels: [UInt: StatusTimeViewModel?]? private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() @@ -29,12 +30,14 @@ final class ReferendumsPresenter { interactor: ReferendumsInteractorInputProtocol, wireframe: ReferendumsWireframeProtocol, viewModelFactory: ReferendumsModelFactoryProtocol, + statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol ) { self.interactor = interactor self.wireframe = wireframe self.viewModelFactory = viewModelFactory + self.statusViewModelFactory = statusViewModelFactory self.logger = logger self.localizationManager = localizationManager } @@ -67,7 +70,7 @@ final class ReferendumsPresenter { referendums: referendums, metadataMapping: referendumsMetadata, votes: votes ?? [:], - chainInfo: .init(chain: chainModel, currentBlock: currentBlock, blockDurartion: blockTime), + chainInfo: .init(chain: chainModel, currentBlock: currentBlock, blockDuration: blockTime), locale: selectedLocale )) @@ -78,16 +81,14 @@ final class ReferendumsPresenter { guard let view = view else { return } - guard let currentBlock = blockNumber, - let blockTime = blockTime, - let referendums = referendums else { + guard let currentBlock = blockNumber, let blockTime = blockTime, let referendums = referendums else { return } - let timeModels = viewModelFactory.createTimeModels( + let timeModels = statusViewModelFactory.createTimeViewModels( referendums: referendums, currentBlock: currentBlock, - blockDurartion: blockTime, + blockDuration: blockTime, locale: selectedLocale ) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 61621d5866..7de9ed3482 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -5,7 +5,7 @@ protocol ReferendumsViewProtocol: ControllerBackedProtocol { func didReceiveChainBalance(viewModel: ChainBalanceViewModel) func update(model: ReferendumsViewModel) - func updateReferendums(time: [UInt: StatusTimeModel?]) + func updateReferendums(time: [UInt: StatusTimeViewModel?]) } protocol ReferendumsPresenterProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 1a738cf69a..19f791aefa 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -88,7 +88,7 @@ extension ReferendumsViewManager: ReferendumsViewProtocol { tableView.reloadData() } - func updateReferendums(time: [UInt: StatusTimeModel?]) { + func updateReferendums(time: [UInt: StatusTimeViewModel?]) { tableView.visibleCells.forEach { cell in guard let referendumCell = cell as? ReferendumTableViewCell, let indexPath = tableView.indexPath(for: cell) else { diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift index b4e4561881..1395236d37 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -141,7 +141,7 @@ extension IconDetailsView.Style { extension UILabel.Style { static let positiveStatusLabel = UILabel.Style( - textColor: R.color.colorDarkGreen(), + textColor: R.color.colorGreen15CF37(), font: .semiBoldCaps1 ) static let neutralStatusLabel = UILabel.Style( diff --git a/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift b/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift index 19829e4dab..1d4a451576 100644 --- a/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift +++ b/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift @@ -2,8 +2,9 @@ import UIKit extension SliderLayer.Style { static let governance = SliderLayer.Style( - firstColor: UIColor(red: 0.081, green: 0.812, blue: 0.215, alpha: 1), - lastColor: UIColor(red: 0.749, green: 0.216, blue: 0.345, alpha: 1), + firstColor: R.color.colorGreen15CF37()!, + lastColor: R.color.colorRedFF3A69()!, + zeroColor: R.color.colorWhite16()!, cornerRadius: 4, dividerSpace: 6 ) @@ -16,7 +17,7 @@ extension SegmentedSliderView.ThumbStyle { width: 3, height: nil, shadow: .init( - color: UIColor(red: 0, green: 0, blue: 0, alpha: 0.72), + color: R.color.colorBlack72()!, opacity: 1, offset: .zero, radius: 8 diff --git a/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift b/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift index feb581f058..4d9096bb4f 100644 --- a/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift +++ b/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift @@ -29,18 +29,18 @@ final class SegmentedSliderView: UIView { let sliderFrame = bounds.inset(by: style.lineInsets) slider.frame = sliderFrame - guard let thumbValue = model.thumbValue, - let thumbStyle = style.thumbStyle else { + guard let thumbStyle = style.thumbStyle else { thumb.frame = .zero return } - let thumbValueDouble = NSDecimalNumber(decimal: thumbValue).doubleValue + let thumbValueDouble = NSDecimalNumber(decimal: model.thumbProgress).doubleValue let originX = sliderFrame.size.width * thumbValueDouble - thumbStyle.width / 2 let thumbHeight = thumbStyle.height ?? bounds.size.height let originY = sliderFrame.midY - thumbHeight / 2 - let origin = CGPoint(x: originX, y: originY) + let origin = CGPoint(x: min(bounds.maxX, max(originX, bounds.minX)), y: originY) let size = CGSize(width: thumbStyle.width, height: thumbHeight) + thumb.frame = CGRect(origin: origin, size: size) } @@ -111,19 +111,19 @@ extension SegmentedSliderView { extension SegmentedSliderView { struct Model { - let thumbValue: Decimal? - let value: Decimal + let thumbProgress: Decimal + let value: Decimal? - init(thumbValue: Decimal? = nil, value: Decimal = 0) { - self.thumbValue = thumbValue + init(thumbProgress: Decimal = 0.0, value: Decimal? = nil) { + self.thumbProgress = thumbProgress self.value = value } } func bind(viewModel: Model) { model = viewModel - slider.gap = NSDecimalNumber(decimal: model.value).doubleValue + slider.gap = model.value.map { CGFloat(NSDecimalNumber(decimal: $0).floatValue) } - setNeedsDisplay() + setNeedsLayout() } } diff --git a/novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift b/novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift index 541f7f8d6f..7c4fb3448d 100644 --- a/novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift +++ b/novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift @@ -5,9 +5,11 @@ final class SliderLayer: CALayer { private let lastSegment: CAShapeLayer private var sliderStyle: Style = .defaultStyle - var gap: CGFloat = 0 { + var gap: CGFloat? { didSet { - setNeedsLayout() + if gap != oldValue { + applyStyleAndLayout() + } } } @@ -15,6 +17,7 @@ final class SliderLayer: CALayer { guard let other = layer as? SliderLayer else { fatalError() } + firstSegment = other.firstSegment lastSegment = other.lastSegment sliderStyle = other.sliderStyle @@ -39,30 +42,54 @@ final class SliderLayer: CALayer { fatalError("init(coder:) has not been implemented") } + private func applyStyleAndLayout() { + if gap != nil { + firstSegment.fillColor = sliderStyle.firstColor.cgColor + lastSegment.fillColor = sliderStyle.lastColor.cgColor + + lastSegment.isHidden = false + } else { + firstSegment.fillColor = sliderStyle.zeroColor.cgColor + + lastSegment.isHidden = true + } + + setNeedsLayout() + } + override func layoutSublayers() { - let lineCalculationSize = CGSize( - width: bounds.width - sliderStyle.dividerSpace, - height: bounds.height - ) - let firstSegmentSize = lineCalculationSize.applying(.init(scaleX: gap, y: 1)) - let lastSegmentSize = lineCalculationSize.applying(.init(scaleX: 1 - gap, y: 1)) - let space = firstSegmentSize.width + sliderStyle.dividerSpace - let lastSegmentOrigin = bounds.origin.applying(.init( - translationX: space, - y: 0 - )) - - let firstPath = UIBezierPath( - roundedRect: .init(origin: bounds.origin, size: firstSegmentSize), - cornerRadius: sliderStyle.cornerRadius - ) - let lastPath = UIBezierPath( - roundedRect: .init(origin: lastSegmentOrigin, size: lastSegmentSize), - cornerRadius: sliderStyle.cornerRadius - ) + if let gap = gap { + let lineCalculationSize = CGSize( + width: bounds.width - sliderStyle.dividerSpace, + height: bounds.height + ) + + let firstSegmentSize = lineCalculationSize.applying(.init(scaleX: gap, y: 1)) + let lastSegmentSize = lineCalculationSize.applying(.init(scaleX: 1 - gap, y: 1)) + let space = firstSegmentSize.width + sliderStyle.dividerSpace + + let lastSegmentOrigin = bounds.origin.applying(.init( + translationX: space, + y: 0 + )) + + let firstPath = UIBezierPath( + roundedRect: .init(origin: bounds.origin, size: firstSegmentSize), + cornerRadius: sliderStyle.cornerRadius + ) + + let lastPath = UIBezierPath( + roundedRect: .init(origin: lastSegmentOrigin, size: lastSegmentSize), + cornerRadius: sliderStyle.cornerRadius + ) - firstSegment.path = firstPath.cgPath - lastSegment.path = lastPath.cgPath + firstSegment.path = firstPath.cgPath + lastSegment.path = lastPath.cgPath + } else { + let path = UIBezierPath(roundedRect: bounds, cornerRadius: sliderStyle.cornerRadius) + + firstSegment.path = path.cgPath + } } } @@ -70,12 +97,14 @@ extension SliderLayer { struct Style { let firstColor: UIColor let lastColor: UIColor + let zeroColor: UIColor let cornerRadius: CGFloat let dividerSpace: CGFloat static let defaultStyle = Style( firstColor: .green, lastColor: .red, + zeroColor: .gray, cornerRadius: 4, dividerSpace: 6 ) @@ -83,8 +112,7 @@ extension SliderLayer { func apply(style: Style) { sliderStyle = style - firstSegment.fillColor = style.firstColor.cgColor - lastSegment.fillColor = style.lastColor.cgColor - setNeedsLayout() + + applyStyleAndLayout() } } diff --git a/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift b/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift index 739fe5a937..44e8ae5063 100644 --- a/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift +++ b/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift @@ -34,6 +34,7 @@ final class ThumbLayer: CALayer { roundedRect: bounds, cornerRadius: thumbStyle.cornerRadius ) + shapeLayer.path = thumbPath.cgPath } } @@ -48,7 +49,9 @@ extension ThumbLayer { func apply(style: Style) { thumbStyle = style + shapeLayer.fillColor = thumbStyle.color.cgColor + setNeedsLayout() } } diff --git a/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift index 2fa3fceb55..2e683fc5b3 100644 --- a/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift +++ b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift @@ -53,30 +53,30 @@ final class VotingProgressView: UIView { extension VotingProgressView { struct Model { - let ayeProgress: String - let passProgress: String - let nayProgress: String - let thresholdModel: ThresholdModel? - let progress: Decimal + let support: TitleIconViewModel? + let approval: ApprovalModel } - struct ThresholdModel { - let titleIcon: TitleIconViewModel? - let value: Decimal + struct ApprovalModel { + let passThreshold: Decimal + let ayeProgress: Decimal? + let ayeMessage: String + let passMessage: String + let nayMessage: String } func bind(viewModel: Model) { slider.bind(viewModel: .init( - thumbValue: viewModel.thresholdModel?.value, - value: viewModel.progress + thumbProgress: viewModel.approval.passThreshold, + value: viewModel.approval.ayeProgress )) - ayeProgressLabel.text = viewModel.ayeProgress - passProgressLabel.text = viewModel.passProgress - nayProgressLabel.text = viewModel.nayProgress + ayeProgressLabel.text = viewModel.approval.ayeMessage + passProgressLabel.text = viewModel.approval.passMessage + nayProgressLabel.text = viewModel.approval.nayMessage - thresholdView.bind(viewModel: viewModel.thresholdModel?.titleIcon) - thresholdView.isHidden = viewModel.thresholdModel?.titleIcon?.title == nil + thresholdView.bind(viewModel: viewModel.support) + thresholdView.isHidden = viewModel.support == nil } } diff --git a/novawallet/Modules/Vote/Governance/View/YourVoteView.swift b/novawallet/Modules/Vote/Governance/View/YourVoteView.swift index 2783681bce..1ded7b6501 100644 --- a/novawallet/Modules/Vote/Governance/View/YourVoteView.swift +++ b/novawallet/Modules/Vote/Governance/View/YourVoteView.swift @@ -104,7 +104,7 @@ extension YourVoteView { extension UILabel.Style { static let ayeType = UILabel.Style( - textColor: R.color.colorDarkGreen(), + textColor: R.color.colorGreen15CF37()!, font: .semiBoldCaps1 ) static let nayType = UILabel.Style( diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift new file mode 100644 index 0000000000..73ab6e05d8 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift @@ -0,0 +1,184 @@ +import Foundation + +protocol ReferendumStatusViewModelFactoryProtocol { + func createTimeViewModel( + for referendum: ReferendumLocal, + currentBlock: BlockNumber, + blockDuration: UInt64, + locale: Locale + ) -> StatusTimeViewModel? +} + +extension ReferendumStatusViewModelFactoryProtocol { + func createTimeViewModels( + referendums: [ReferendumLocal], + currentBlock: BlockNumber, + blockDuration: UInt64, + locale: Locale + ) -> [UInt: StatusTimeViewModel?] { + referendums.reduce(into: [UInt: StatusTimeViewModel?]()) { result, referendum in + result[referendum.index] = createTimeViewModel( + for: referendum, + currentBlock: currentBlock, + blockDuration: blockDuration, + locale: locale + ) + } + } +} + +final class ReferendumStatusViewModelFactory { + private func createTimeViewModel( + state: ReferendumStateLocal, + atBlock: Moment, + currentBlock: BlockNumber, + blockDuration: UInt64, + timeStringProvider: @escaping (String, [String]?) -> String, + locale: Locale + ) -> StatusTimeViewModel? { + let time = calculateTime( + block: atBlock, + currentBlock: currentBlock, + blockDuration: blockDuration + ) + guard let timeModel = createTimeViewModel( + time: time, + timeStringProvider: timeStringProvider, + state: state, + locale: locale + ) else { + return nil + } + return .init(viewModel: timeModel, timeInterval: time) { [weak self] in + self?.createTimeViewModel( + time: $0, + timeStringProvider: timeStringProvider, + state: state, + locale: locale + ) + } + } + + private func createTimeViewModel( + time: TimeInterval, + timeStringProvider: (String, [String]?) -> String, + state: ReferendumStateLocal, + locale: Locale + ) -> ReferendumInfoView.Model.Time? { + guard let localizedDaysHours = time.localizedDaysOrTime(for: locale) else { + return nil + } + let timeString = timeStringProvider(localizedDaysHours, locale.rLanguages) + let timeModel = isUrgent(state: state, time: time).map { isUrgent in + ReferendumInfoView.Model.Time( + titleIcon: .init( + title: timeString, + icon: isUrgent ? R.image.iconFire() : R.image.iconLightPending() + ), + isUrgent: isUrgent + ) + } + return timeModel + } + + private func calculateTime(block: Moment, currentBlock: BlockNumber, blockDuration: UInt64) -> TimeInterval { + currentBlock.secondsTo(block: block, blockDuration: blockDuration) + } + + private func isUrgent(state: ReferendumStateLocal, time: TimeInterval) -> Bool? { + switch state { + case .preparing: + return time.hoursFromSeconds <= 3 + case .deciding: + return time.daysFromSeconds < 1 + case .approved: + return time.daysFromSeconds < 1 + case .rejected: + return time.daysFromSeconds < 1 + case .cancelled, .timedOut, .killed, .executed: + return nil + } + } +} + +extension ReferendumStatusViewModelFactory: ReferendumStatusViewModelFactoryProtocol { + func createTimeViewModel( + for referendum: ReferendumLocal, + currentBlock: BlockNumber, + blockDuration: UInt64, + locale: Locale + ) -> StatusTimeViewModel? { + let strings = R.string.localizable.self + switch referendum.state { + case let .preparing(model): + if model.deposit == nil { + let title = strings.governanceReferendumsTimeWaitingDeposit(preferredLanguages: locale.rLanguages) + let timeViewModel = ReferendumInfoView.Model.Time( + titleIcon: .init(title: title, icon: R.image.iconLightPending()), + isUrgent: false + ) + + return StatusTimeViewModel(viewModel: timeViewModel, timeInterval: nil) { _ in + timeViewModel + } + } else if currentBlock >= model.preparingPeriod { + return createTimeViewModel( + state: referendum.state, + atBlock: max(currentBlock, model.timeoutAt), + currentBlock: currentBlock, + blockDuration: blockDuration, + timeStringProvider: strings.governanceReferendumsTimeTimeout, + locale: locale + ) + } else { + return createTimeViewModel( + state: referendum.state, + atBlock: model.preparingEnd, + currentBlock: currentBlock, + blockDuration: blockDuration, + timeStringProvider: strings.governanceReferendumsTimeDeciding, + locale: locale + ) + } + case let .deciding(model): + switch model.voting { + case let .supportAndVotes(supportAndVotes): + if supportAndVotes.isPassing(at: currentBlock), + let confirmationUntil = model.confirmationUntil { + return createTimeViewModel( + state: referendum.state, + atBlock: confirmationUntil, + currentBlock: currentBlock, + blockDuration: blockDuration, + timeStringProvider: strings.governanceReferendumsTimeApprove, + locale: locale + ) + } else { + return createTimeViewModel( + state: referendum.state, + atBlock: model.rejectedAt, + currentBlock: currentBlock, + blockDuration: blockDuration, + timeStringProvider: strings.governanceReferendumsTimeReject, + locale: locale + ) + } + } + case let .approved(model): + guard let whenEnactment = model.whenEnactment else { + return nil + } + + return createTimeViewModel( + state: referendum.state, + atBlock: whenEnactment, + currentBlock: currentBlock, + blockDuration: blockDuration, + timeStringProvider: strings.governanceReferendumsTimeExecute, + locale: locale + ) + case .rejected, .cancelled, .timedOut, .killed, .executed: + return nil + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift new file mode 100644 index 0000000000..3147060487 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -0,0 +1,414 @@ +import Foundation +import SoraFoundation +import BigInt + +struct ReferendumsModelFactoryInput { + let referendums: [ReferendumLocal] + let metadataMapping: [Referenda.ReferendumIndex: ReferendumMetadataLocal]? + let votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal] + let chainInfo: ChainInformation + let locale: Locale + + struct ChainInformation { + let chain: ChainModel + let currentBlock: BlockNumber + let blockDuration: UInt64 + } +} + +protocol ReferendumsModelFactoryProtocol { + func createSections(input: ReferendumsModelFactoryInput) -> [ReferendumsSection] +} + +final class ReferendumsModelFactory { + private typealias Input = ReferendumsModelFactoryInput + private typealias Strings = R.string.localizable + + private struct StatusParams { + let referendum: ReferendumLocal + let metadata: ReferendumMetadataLocal? + let chainInfo: Input.ChainInformation + let votes: ReferendumAccountVoteLocal? + } + + let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol + let localizedPercentFormatter: LocalizableResource + let localizedQuantityFormatter: LocalizableResource + let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol + + init( + statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol, + assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, + percentFormatter: LocalizableResource, + quantityNumberFormatter: LocalizableResource + ) { + self.statusViewModelFactory = statusViewModelFactory + self.assetBalanceFormatterFactory = assetBalanceFormatterFactory + localizedPercentFormatter = percentFormatter + localizedQuantityFormatter = quantityNumberFormatter + } + + private func provideCommonReferendumCellViewModel( + status: ReferendumInfoView.Model.Status, + params: StatusParams, + locale: Locale + ) -> ReferendumView.Model { + let yourVotesModel = createVotesViewModel( + votes: params.votes, + chainAsset: params.chainInfo.chain.utilityAsset(), + locale: locale + ) + return .init( + referendumInfo: .init( + status: status, + time: nil, + title: params.metadata?.name ?? "", + track: nil + ), + progress: nil, + yourVotes: yourVotesModel + ) + } + + private func providePreparingReferendumCellViewModel( + _ model: ReferendumStateLocal.Preparing, + params: StatusParams, + locale: Locale + ) -> ReferendumView.Model { + let timeModel = statusViewModelFactory.createTimeViewModel( + for: params.referendum, + currentBlock: params.chainInfo.currentBlock, + blockDuration: params.chainInfo.blockDuration, + locale: locale + ) + + let title = model.inQueue ? + Strings.governanceReferendumsStatusPreparingInqueue(preferredLanguages: locale.rLanguages) : + Strings.governanceReferendumsStatusPreparing(preferredLanguages: locale.rLanguages) + + switch model.voting { + case let .supportAndVotes(supportAndVotes): + let progressViewModel = createVotingProgressViewModel( + supportAndVotes: supportAndVotes, + chain: params.chainInfo.chain, + currentBlock: params.chainInfo.currentBlock, + locale: locale + ) + let yourVotesModel = createVotesViewModel( + votes: params.votes, + chainAsset: params.chainInfo.chain.utilityAsset(), + locale: locale + ) + let trackName = model.track.name.replacingSnakeCase().uppercased() + + let referendumNumber = localizedQuantityFormatter.value(for: locale).string( + from: NSNumber(value: params.referendum.index) + ) + + return .init( + referendumInfo: .init( + status: .init(name: title.uppercased(), kind: .neutral), + time: timeModel?.viewModel, + title: params.metadata?.name ?? "", + track: .init( + titleIcon: .init(title: trackName, icon: nil), + referendumNumber: referendumNumber.map { "#" + $0 } + ) + ), + progress: progressViewModel, + yourVotes: yourVotesModel + ) + } + } + + private func createVotesViewModel( + votes: ReferendumAccountVoteLocal?, + chainAsset: AssetModel?, + locale: Locale + ) -> YourVotesView.Model? { + guard let votes = votes, + let chainAsset = chainAsset, + votes.ayes + votes.nays > 0 else { + return nil + } + + let inputFormatter = assetBalanceFormatterFactory.createInputFormatter(for: chainAsset.displayInfo) + + let formatVotes: (BigUInt) -> String = { votesInPlank in + guard let votes = Decimal.fromSubstrateAmount( + votesInPlank, + precision: Int16(chainAsset.precision) + ) else { + return "" + } + let votesString = inputFormatter.value(for: locale).stringFromDecimal(votes) ?? "" + return Strings.governanceReferendumsYourVote( + votesString, + preferredLanguages: locale.rLanguages + ) + } + let ayesModel = votes.ayes > 0 ? YourVoteView.Model( + title: Strings.governanceAye(preferredLanguages: locale.rLanguages).uppercased(), + description: formatVotes(votes.ayes) + ) : nil + let naysModel = votes.nays > 0 ? YourVoteView.Model( + title: Strings.governanceNay(preferredLanguages: locale.rLanguages).uppercased(), + description: formatVotes(votes.nays) + ) : nil + return .init( + aye: ayesModel, + nay: naysModel + ) + } + + private func provideDecidingReferendumCellViewModel( + _ model: ReferendumStateLocal.Deciding, + params: StatusParams, + locale: Locale + ) -> ReferendumView.Model { + switch model.voting { + case let .supportAndVotes(supportAndVotes): + let timeModel = statusViewModelFactory.createTimeViewModel( + for: params.referendum, + currentBlock: params.chainInfo.currentBlock, + blockDuration: params.chainInfo.blockDuration, + locale: locale + ) + + let progressViewModel = createVotingProgressViewModel( + supportAndVotes: supportAndVotes, + chain: params.chainInfo.chain, + currentBlock: params.chainInfo.currentBlock, + locale: locale + ) + let isPassing = supportAndVotes.isPassing(at: params.chainInfo.currentBlock) + let statusName = isPassing ? + Strings.governanceReferendumsStatusPassing(preferredLanguages: locale.rLanguages) : + Strings.governanceReferendumsStatusNotPassing(preferredLanguages: locale.rLanguages) + let statusKind: ReferendumInfoView.Model.StatusKind = isPassing ? .positive : .negative + let yourVotesModel = createVotesViewModel( + votes: params.votes, + chainAsset: params.chainInfo.chain.utilityAsset(), + locale: locale + ) + let trackName = model.track.name.replacingSnakeCase().uppercased() + + let quantityFormatter = localizedQuantityFormatter.value(for: locale) + let referendumNumber = quantityFormatter.string(from: NSNumber(value: params.referendum.index)) + + return .init( + referendumInfo: .init( + status: .init(name: statusName.uppercased(), kind: statusKind), + time: timeModel?.viewModel, + title: params.metadata?.name, + track: .init( + titleIcon: .init(title: trackName, icon: nil), + referendumNumber: referendumNumber.map { "#" + $0 } + ) + ), + progress: progressViewModel, + yourVotes: yourVotesModel + ) + } + } + + private func provideApprovedReferendumCellViewModel( + _: ReferendumStateLocal.Approved, + params: StatusParams, + locale: Locale + ) -> ReferendumView.Model { + let timeModel = statusViewModelFactory.createTimeViewModel( + for: params.referendum, + currentBlock: params.chainInfo.currentBlock, + blockDuration: params.chainInfo.blockDuration, + locale: locale + ) + + let title = Strings.governanceReferendumsStatusApproved(preferredLanguages: locale.rLanguages) + + let yourVotesModel = createVotesViewModel( + votes: params.votes, + chainAsset: params.chainInfo.chain.utilityAsset(), + locale: locale + ) + + return .init( + referendumInfo: .init( + status: .init(name: title.uppercased(), kind: .positive), + time: timeModel?.viewModel, + title: params.metadata?.name, + track: nil + ), + progress: nil, + yourVotes: yourVotesModel + ) + } + + private func createVotingSupportProgressViewModel( + supportAndVotes: SupportAndVotesLocal, + chain: ChainModel, + currentBlock: BlockNumber, + locale: Locale + ) -> TitleIconViewModel? { + guard + let chainAsset = chain.utilityAsset(), + let supportThreshold = supportAndVotes.supportFunction?.calculateThreshold(for: currentBlock) else { + return nil + } + + let targetThreshold = Decimal.fromSubstrateAmount( + supportAndVotes.totalIssuance, + precision: Int16(chainAsset.precision) + ) + let threshold = Decimal.fromSubstrateAmount( + supportAndVotes.support, + precision: Int16(chainAsset.precision) + ) + let isCompleted = supportAndVotes.supportFraction >= supportThreshold + + let image = isCompleted ? + R.image.iconCheckmark()?.withTintColor(R.color.colorGreen15CF37()!) : + R.image.iconClose()?.withTintColor(R.color.colorRedFF3A69()!) + + let tokenFormatter = assetBalanceFormatterFactory.createTokenFormatter(for: chainAsset.displayInfo) + let amountFormatter = assetBalanceFormatterFactory.createDisplayFormatter(for: chainAsset.displayInfo) + + let targetThresholdString = targetThreshold.map { + tokenFormatter.value(for: locale).stringFromDecimal($0) ?? "" + } ?? "" + + let thresholdString = threshold.map { + amountFormatter.value(for: locale).stringFromDecimal($0) ?? "" + } ?? "" + + let text = R.string.localizable.governanceReferendumsThreshold(thresholdString, targetThresholdString) + return .init(title: text, icon: image) + } + + private func createVotingApprovalProgressViewModel( + supportAndVotes: SupportAndVotesLocal, + currentBlock: BlockNumber, + locale: Locale + ) -> VotingProgressView.ApprovalModel { + let ayeProgressString: String + let nayProgressString: String + + let percentFormatter = localizedPercentFormatter.value(for: locale) + + if let approvalFraction = supportAndVotes.approvalFraction { + ayeProgressString = percentFormatter.stringFromDecimal(approvalFraction) ?? "" + nayProgressString = percentFormatter.stringFromDecimal(approvalFraction) ?? "" + } else { + ayeProgressString = percentFormatter.stringFromDecimal(0) ?? "" + nayProgressString = percentFormatter.stringFromDecimal(0) ?? "" + } + + let passThreshold = supportAndVotes.approvalFunction?.calculateThreshold(for: currentBlock) ?? 0 + let passThresholdString = percentFormatter.stringFromDecimal(passThreshold) ?? "" + + return .init( + passThreshold: passThreshold, + ayeProgress: supportAndVotes.approvalFraction, + ayeMessage: Strings.governanceAyesFormat(ayeProgressString, preferredLanguages: locale.rLanguages), + passMessage: Strings.governanceToPassFormat(passThresholdString, preferredLanguages: locale.rLanguages), + nayMessage: Strings.governanceNaysFormat(nayProgressString, preferredLanguages: locale.rLanguages) + ) + } + + private func createVotingProgressViewModel( + supportAndVotes: SupportAndVotesLocal, + chain: ChainModel, + currentBlock: BlockNumber, + locale: Locale + ) -> VotingProgressView.Model { + let supportModel = createVotingSupportProgressViewModel( + supportAndVotes: supportAndVotes, + chain: chain, + currentBlock: currentBlock, + locale: locale + ) + + let approvalModel = createVotingApprovalProgressViewModel( + supportAndVotes: supportAndVotes, + currentBlock: currentBlock, + locale: locale + ) + + return .init(support: supportModel, approval: approvalModel) + } +} + +extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { + func createSections(input: ReferendumsModelFactoryInput) -> [ReferendumsSection] { + var active: [ReferendumsCellViewModel] = [] + var completed: [ReferendumsCellViewModel] = [] + + input.referendums.forEach { referendum in + let index = Referenda.ReferendumIndex(referendum.index) + let metadata = input.metadataMapping?[index] + + let params = StatusParams( + referendum: referendum, + metadata: metadata, + chainInfo: input.chainInfo, + votes: input.votes[index] + ) + + let model = createReferendumCellViewModel( + state: referendum.state, + params: params, + locale: input.locale + ) + + let viewModel = ReferendumsCellViewModel( + referendumIndex: referendum.index, + viewModel: .loaded(value: model) + ) + + referendum.state.completed ? completed.append(viewModel) : active.append(viewModel) + } + var sections: [ReferendumsSection] = [] + if !active.isEmpty { + let title = Strings.governanceReferendumsActive(preferredLanguages: input.locale.rLanguages) + sections.append(.active(.loaded(value: title), active)) + } + if !completed.isEmpty { + let title = Strings.governanceReferendumsCompleted(preferredLanguages: input.locale.rLanguages) + sections.append(.completed(.loaded(value: title), completed)) + } + return sections + } + + private func createReferendumCellViewModel( + state: ReferendumStateLocal, + params: StatusParams, + locale: Locale + ) -> ReferendumView.Model { + let status: ReferendumInfoView.Model.Status + switch state { + case let .preparing(model): + return providePreparingReferendumCellViewModel(model, params: params, locale: locale) + case let .deciding(model): + return provideDecidingReferendumCellViewModel(model, params: params, locale: locale) + case let .approved(model): + return provideApprovedReferendumCellViewModel(model, params: params, locale: locale) + case .rejected: + let statusName = Strings.governanceReferendumsStatusRejected(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .negative) + case .cancelled: + let statusName = Strings.governanceReferendumsStatusCancelled(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .neutral) + case .timedOut: + let statusName = Strings.governanceReferendumsStatusTimedOut(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .neutral) + case .killed: + let statusName = Strings.governanceReferendumsStatusKilled(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .negative) + case .executed: + let statusName = Strings.governanceReferendumsStatusExecuted(preferredLanguages: locale.rLanguages) + status = .init(name: statusName, kind: .positive) + } + + return provideCommonReferendumCellViewModel(status: status, params: params, locale: locale) + } +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumsViewModel.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsViewModel.swift similarity index 100% rename from novawallet/Modules/Vote/Governance/Model/ReferendumsViewModel.swift rename to novawallet/Modules/Vote/Governance/ViewModel/ReferendumsViewModel.swift diff --git a/novawallet/Modules/Vote/Governance/Model/StatusTimeModel.swift b/novawallet/Modules/Vote/Governance/ViewModel/StatusTimeViewModel.swift similarity index 86% rename from novawallet/Modules/Vote/Governance/Model/StatusTimeModel.swift rename to novawallet/Modules/Vote/Governance/ViewModel/StatusTimeViewModel.swift index f4cb8ad670..c24225e94f 100644 --- a/novawallet/Modules/Vote/Governance/Model/StatusTimeModel.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/StatusTimeViewModel.swift @@ -1,6 +1,6 @@ import Foundation -struct StatusTimeModel { +struct StatusTimeViewModel { let viewModel: ReferendumInfoView.Model.Time let timeInterval: TimeInterval? let updateModelClosure: (TimeInterval) -> ReferendumInfoView.Model.Time? diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index 47e51cd0ec..87bb5fc930 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -185,16 +185,21 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { let percentFormatter = NumberFormatter.percent percentFormatter.roundingMode = .halfEven + + let statusViewModelFactory = ReferendumStatusViewModelFactory() + let viewModelFactory = ReferendumsModelFactory( + statusViewModelFactory: statusViewModelFactory, assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), - percentFormatter: percentFormatter, - referendumNumberFormatter: .quantity + percentFormatter: percentFormatter.localizableResource(), + quantityNumberFormatter: NumberFormatter.quantity.localizableResource() ) let presenter = ReferendumsPresenter( interactor: interactor, wireframe: wireframe, viewModelFactory: viewModelFactory, + statusViewModelFactory: statusViewModelFactory, localizationManager: localizationManager, logger: logger ) diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 5922a056f8..f998feff01 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1001,3 +1001,8 @@ "governance.referendums.your.vote" = "Your vote: %@ votes"; "governance.referendums.active" = "Ongoing"; "governance.referendums.completed" = "Completed"; +"governance.ayes.format" = "Aye: %@"; +"governance.nays.format" = "Nay: %@"; +"governance.to.pass.format" = "To pass: %@"; +"governance.aye" = "Aye"; +"governance.nay" = "Nay"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 82c78b6268..989ab9a5d2 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1001,3 +1001,9 @@ "governance.referendums.your.vote" = "Ваше голосование: %@ голосов"; "governance.referendums.active" = "Активные"; "governance.referendums.completed" = "Завершённые"; + +"governance.ayes.format" = "За: %@"; +"governance.nays.format" = "Против: %@"; +"governance.to.pass.format" = "Для одобрения: %@"; +"governance.aye" = "За"; +"governance.nay" = "Против"; From 74b41f99ffb7c331a1a83bebe9f20cc81e51c517 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 13 Oct 2022 14:05:05 +0500 Subject: [PATCH 036/229] fix views --- novawallet.xcodeproj/project.pbxproj | 16 ++--- .../View/Slider/GovernanceStyle.swift | 4 +- .../View/Slider/SegmentedSliderView.swift | 12 ++-- .../{SliderLayer.swift => SliderView.swift} | 69 ++++++++----------- .../Governance/View/Slider/ThumbLayer.swift | 57 --------------- .../Governance/View/Slider/ThumbView.swift | 35 ++++++++++ .../ViewModel/ReferendumsModelFactory.swift | 2 +- 7 files changed, 79 insertions(+), 116 deletions(-) rename novawallet/Modules/Vote/Governance/View/Slider/{SliderLayer.swift => SliderView.swift} (53%) delete mode 100644 novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift create mode 100644 novawallet/Modules/Vote/Governance/View/Slider/ThumbView.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index bdc49d62ed..684076ea00 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2158,8 +2158,8 @@ 85A093F6055DDD2E2E9253F2 /* ControllerAccountProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F829E7F8B39EE7D977001510 /* ControllerAccountProtocols.swift */; }; 86EB789787B731691B36C827 /* OnChainTransferSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1A2F7E5E278FDCC89FE097 /* OnChainTransferSetupPresenter.swift */; }; 87F7556E02F6F5BB6F1B1AEA /* ParitySignerTxQrViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A5DCA28ABF42D342BBDF9A /* ParitySignerTxQrViewLayout.swift */; }; - 880059D828EEBC0200E87B9B /* SliderLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059D728EEBC0200E87B9B /* SliderLayer.swift */; }; - 880059DA28EF092800E87B9B /* ThumbLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059D928EF092800E87B9B /* ThumbLayer.swift */; }; + 880059D828EEBC0200E87B9B /* SliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059D728EEBC0200E87B9B /* SliderView.swift */; }; + 880059DA28EF092800E87B9B /* ThumbView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059D928EF092800E87B9B /* ThumbView.swift */; }; 880059DC28EF092F00E87B9B /* SegmentedSliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059DB28EF092F00E87B9B /* SegmentedSliderView.swift */; }; 880059DF28EF09E100E87B9B /* GovernanceStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059DE28EF09E100E87B9B /* GovernanceStyle.swift */; }; 880059E128EF0A5C00E87B9B /* VotingProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059E028EF0A5C00E87B9B /* VotingProgressView.swift */; }; @@ -4994,8 +4994,8 @@ 86F7A369E31DCB9ABD556EE9 /* CrowdloanListPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanListPresenter.swift; sourceTree = ""; }; 86F9063B2DF46E7B65B5248E /* Pods_novawalletAll_novawalletIntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_novawalletAll_novawalletIntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 87CD8C618D61C78EA8C58532 /* ParitySignerTxScanViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerTxScanViewLayout.swift; sourceTree = ""; }; - 880059D728EEBC0200E87B9B /* SliderLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderLayer.swift; sourceTree = ""; }; - 880059D928EF092800E87B9B /* ThumbLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbLayer.swift; sourceTree = ""; }; + 880059D728EEBC0200E87B9B /* SliderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderView.swift; sourceTree = ""; }; + 880059D928EF092800E87B9B /* ThumbView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbView.swift; sourceTree = ""; }; 880059DB28EF092F00E87B9B /* SegmentedSliderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentedSliderView.swift; sourceTree = ""; }; 880059DE28EF09E100E87B9B /* GovernanceStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceStyle.swift; sourceTree = ""; }; 880059E028EF0A5C00E87B9B /* VotingProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VotingProgressView.swift; sourceTree = ""; }; @@ -11860,8 +11860,8 @@ 880059DD28EF093400E87B9B /* Slider */ = { isa = PBXGroup; children = ( - 880059D728EEBC0200E87B9B /* SliderLayer.swift */, - 880059D928EF092800E87B9B /* ThumbLayer.swift */, + 880059D728EEBC0200E87B9B /* SliderView.swift */, + 880059D928EF092800E87B9B /* ThumbView.swift */, 880059DB28EF092F00E87B9B /* SegmentedSliderView.swift */, 880059DE28EF09E100E87B9B /* GovernanceStyle.swift */, ); @@ -15173,7 +15173,7 @@ 84E172CF28BE468D00DC85B6 /* MessageSheetPresentable.swift in Sources */, 8487583727F06AF300495306 /* AddressScanDelegate.swift in Sources */, 3E480EEAF501AEB5D543506D /* UsernameSetupPresenter.swift in Sources */, - 880059DA28EF092800E87B9B /* ThumbLayer.swift in Sources */, + 880059DA28EF092800E87B9B /* ThumbView.swift in Sources */, 84F4387525D9C6EB00AEDA56 /* SubstrateDataProviderFactory.swift in Sources */, 841BFD6D27BA8E70000A16CE /* MetamaskSwitchChain.swift in Sources */, 84D2F1AC2774B3A00040C680 /* CustomSearchBar.swift in Sources */, @@ -15401,7 +15401,7 @@ 84D8753D28EB17B2004065BD /* GovernanceSharedState.swift in Sources */, 8436EDE725895846004D9E97 /* PurchaseProvider.swift in Sources */, AEF50556261A04AD0098574D /* MoonpayProvider.swift in Sources */, - 880059D828EEBC0200E87B9B /* SliderLayer.swift in Sources */, + 880059D828EEBC0200E87B9B /* SliderView.swift in Sources */, 84FB29942639ABD700BE0FCD /* YourValidatorList+SelectionStart.swift in Sources */, 84DB9E8A26409E8200F23DD3 /* StakingRedeemLayout.swift in Sources */, 84F3B27627F4175500D64CF5 /* PhishingSite.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift b/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift index 1d4a451576..7a86d62c41 100644 --- a/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift +++ b/novawallet/Modules/Vote/Governance/View/Slider/GovernanceStyle.swift @@ -1,7 +1,7 @@ import UIKit -extension SliderLayer.Style { - static let governance = SliderLayer.Style( +extension SliderView.Style { + static let governance = SliderView.Style( firstColor: R.color.colorGreen15CF37()!, lastColor: R.color.colorRedFF3A69()!, zeroColor: R.color.colorWhite16()!, diff --git a/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift b/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift index 4d9096bb4f..a58006b715 100644 --- a/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift +++ b/novawallet/Modules/Vote/Governance/View/Slider/SegmentedSliderView.swift @@ -4,16 +4,16 @@ final class SegmentedSliderView: UIView { private var style: Style = .defaultStyle private var model: Model = .init() - let slider = SliderLayer() - let thumb = ThumbLayer() + let slider = SliderView() + let thumb = ThumbView() override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .clear - layer.addSublayer(slider) - layer.addSublayer(thumb) + addSubview(slider) + addSubview(thumb) apply(style: style) } @@ -50,7 +50,7 @@ final class SegmentedSliderView: UIView { } extension SegmentedSliderView { - typealias SliderStyle = SliderLayer.Style + typealias SliderStyle = SliderView.Style struct Style { let lineInsets: UIEdgeInsets let sliderStyle: SliderStyle @@ -99,7 +99,7 @@ extension SegmentedSliderView { style.thumbStyle.map { thumb.apply(style: .init(color: $0.color, cornerRadius: $0.cornerRadius)) - thumb.shadowColor = $0.shadow.color.cgColor + thumb.shadowColor = $0.shadow.color thumb.shadowOpacity = $0.shadow.opacity thumb.shadowOffset = $0.shadow.offset thumb.shadowRadius = $0.shadow.radius diff --git a/novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift b/novawallet/Modules/Vote/Governance/View/Slider/SliderView.swift similarity index 53% rename from novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift rename to novawallet/Modules/Vote/Governance/View/Slider/SliderView.swift index 7c4fb3448d..87b35243fa 100644 --- a/novawallet/Modules/Vote/Governance/View/Slider/SliderLayer.swift +++ b/novawallet/Modules/Vote/Governance/View/Slider/SliderView.swift @@ -1,8 +1,15 @@ import UIKit +import SoraUI + +final class SliderView: UIView { + private let firstSegment: RoundedView = .create { view in + view.shadowOpacity = 0.0 + } + + private let lastSegment: RoundedView = .create { view in + view.shadowOpacity = 0.0 + } -final class SliderLayer: CALayer { - private let firstSegment: CAShapeLayer - private let lastSegment: CAShapeLayer private var sliderStyle: Style = .defaultStyle var gap: CGFloat? { @@ -13,26 +20,11 @@ final class SliderLayer: CALayer { } } - override init(layer: Any) { - guard let other = layer as? SliderLayer else { - fatalError() - } - - firstSegment = other.firstSegment - lastSegment = other.lastSegment - sliderStyle = other.sliderStyle - - super.init(layer: layer) - } - - override init() { - firstSegment = CAShapeLayer() - lastSegment = CAShapeLayer() + override init(frame: CGRect) { + super.init(frame: frame) - super.init() - - addSublayer(firstSegment) - addSublayer(lastSegment) + addSubview(firstSegment) + addSubview(lastSegment) apply(style: sliderStyle) } @@ -43,13 +35,16 @@ final class SliderLayer: CALayer { } private func applyStyleAndLayout() { + firstSegment.cornerRadius = sliderStyle.cornerRadius + lastSegment.cornerRadius = sliderStyle.cornerRadius + if gap != nil { - firstSegment.fillColor = sliderStyle.firstColor.cgColor - lastSegment.fillColor = sliderStyle.lastColor.cgColor + firstSegment.fillColor = sliderStyle.firstColor + lastSegment.fillColor = sliderStyle.lastColor lastSegment.isHidden = false } else { - firstSegment.fillColor = sliderStyle.zeroColor.cgColor + firstSegment.fillColor = sliderStyle.zeroColor lastSegment.isHidden = true } @@ -57,7 +52,9 @@ final class SliderLayer: CALayer { setNeedsLayout() } - override func layoutSublayers() { + override func layoutSubviews() { + super.layoutSubviews() + if let gap = gap { let lineCalculationSize = CGSize( width: bounds.width - sliderStyle.dividerSpace, @@ -73,27 +70,15 @@ final class SliderLayer: CALayer { y: 0 )) - let firstPath = UIBezierPath( - roundedRect: .init(origin: bounds.origin, size: firstSegmentSize), - cornerRadius: sliderStyle.cornerRadius - ) - - let lastPath = UIBezierPath( - roundedRect: .init(origin: lastSegmentOrigin, size: lastSegmentSize), - cornerRadius: sliderStyle.cornerRadius - ) - - firstSegment.path = firstPath.cgPath - lastSegment.path = lastPath.cgPath + firstSegment.frame = CGRect(origin: bounds.origin, size: firstSegmentSize) + lastSegment.frame = CGRect(origin: lastSegmentOrigin, size: lastSegmentSize) } else { - let path = UIBezierPath(roundedRect: bounds, cornerRadius: sliderStyle.cornerRadius) - - firstSegment.path = path.cgPath + firstSegment.frame = bounds } } } -extension SliderLayer { +extension SliderView { struct Style { let firstColor: UIColor let lastColor: UIColor diff --git a/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift b/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift deleted file mode 100644 index 44e8ae5063..0000000000 --- a/novawallet/Modules/Vote/Governance/View/Slider/ThumbLayer.swift +++ /dev/null @@ -1,57 +0,0 @@ -import UIKit - -final class ThumbLayer: CALayer { - private var thumbStyle: Style = .defaultStyle - private let shapeLayer: CAShapeLayer - - override init() { - shapeLayer = .init() - - super.init() - - addSublayer(shapeLayer) - apply(style: thumbStyle) - } - - override init(layer: Any) { - guard let other = layer as? ThumbLayer else { - fatalError() - } - thumbStyle = other.thumbStyle - shapeLayer = other.shapeLayer - - super.init(layer: layer) - apply(style: thumbStyle) - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSublayers() { - let thumbPath = UIBezierPath( - roundedRect: bounds, - cornerRadius: thumbStyle.cornerRadius - ) - - shapeLayer.path = thumbPath.cgPath - } -} - -extension ThumbLayer { - struct Style { - let color: UIColor - let cornerRadius: CGFloat - - static let defaultStyle = Style(color: .gray, cornerRadius: 10) - } - - func apply(style: Style) { - thumbStyle = style - - shapeLayer.fillColor = thumbStyle.color.cgColor - - setNeedsLayout() - } -} diff --git a/novawallet/Modules/Vote/Governance/View/Slider/ThumbView.swift b/novawallet/Modules/Vote/Governance/View/Slider/ThumbView.swift new file mode 100644 index 0000000000..d62b768949 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/Slider/ThumbView.swift @@ -0,0 +1,35 @@ +import UIKit +import SoraUI + +final class ThumbView: RoundedView { + private var thumbStyle: Style = .defaultStyle + + override init(frame: CGRect) { + super.init(frame: frame) + + apply(style: thumbStyle) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension ThumbView { + struct Style { + let color: UIColor + let cornerRadius: CGFloat + + static let defaultStyle = Style(color: .gray, cornerRadius: 10) + } + + func apply(style: Style) { + thumbStyle = style + + fillColor = thumbStyle.color + cornerRadius = style.cornerRadius + + setNeedsLayout() + } +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 3147060487..4cb669c2b5 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -297,7 +297,7 @@ final class ReferendumsModelFactory { if let approvalFraction = supportAndVotes.approvalFraction { ayeProgressString = percentFormatter.stringFromDecimal(approvalFraction) ?? "" - nayProgressString = percentFormatter.stringFromDecimal(approvalFraction) ?? "" + nayProgressString = percentFormatter.stringFromDecimal(1 - approvalFraction) ?? "" } else { ayeProgressString = percentFormatter.stringFromDecimal(0) ?? "" nayProgressString = percentFormatter.stringFromDecimal(0) ?? "" From 5d1f88f046fdf5dd3e9d94835492767f0f6ff127 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 13 Oct 2022 18:00:52 +0500 Subject: [PATCH 037/229] fix voting progress --- novawallet.xcodeproj/project.pbxproj | 4 + novawallet/Assets.xcassets/gov/Contents.json | 6 ++ .../iconGovCrowdloan.imageset/Contents.json | 12 +++ .../iconGovCrowdloan.pdf | Bin 0 -> 4924 bytes .../iconGovFellowship.imageset/Contents.json | 12 +++ .../iconGovFellowship.pdf | Bin 0 -> 5657 bytes .../iconGovGovernance.imageset/Contents.json | 12 +++ .../iconGovGovernance.pdf | Bin 0 -> 1858 bytes .../gov/iconGovStaking.imageset/Contents.json | 12 +++ .../iconGovStaking.pdf | Bin 0 -> 4825 bytes .../iconGovTreasury.imageset/Contents.json | 12 +++ .../iconGovTreasury.pdf | Bin 0 -> 1549 bytes .../Foundation/NumberFormatter.swift | 12 +++ .../ReferendumDecidingFunctionProtocol.swift | 4 +- .../Operation/Gov2LocalMappingFactory.swift | 16 +++- .../Referendums/ReferendumsPresenter.swift | 1 + .../Governance/View/ReferendumInfoView.swift | 40 ++++++-- .../ViewModel/ReferendumTrackType.swift | 90 ++++++++++++++++++ .../ViewModel/ReferendumsModelFactory.swift | 73 ++++++++------ .../Parent/VoteChildPresenterFactory.swift | 7 +- novawallet/en.lproj/Localizable.strings | 15 +++ novawallet/ru.lproj/Localizable.strings | 15 +++ 22 files changed, 300 insertions(+), 43 deletions(-) create mode 100644 novawallet/Assets.xcassets/gov/Contents.json create mode 100644 novawallet/Assets.xcassets/gov/iconGovCrowdloan.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/gov/iconGovCrowdloan.imageset/iconGovCrowdloan.pdf create mode 100644 novawallet/Assets.xcassets/gov/iconGovFellowship.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/gov/iconGovFellowship.imageset/iconGovFellowship.pdf create mode 100644 novawallet/Assets.xcassets/gov/iconGovGovernance.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/gov/iconGovGovernance.imageset/iconGovGovernance.pdf create mode 100644 novawallet/Assets.xcassets/gov/iconGovStaking.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/gov/iconGovStaking.imageset/iconGovStaking.pdf create mode 100644 novawallet/Assets.xcassets/gov/iconGovTreasury.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/gov/iconGovTreasury.imageset/iconGovTreasury.pdf create mode 100644 novawallet/Modules/Vote/Governance/ViewModel/ReferendumTrackType.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 684076ea00..c8041961c5 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -893,6 +893,7 @@ 845532D02684690D00C2645D /* ParachainSlotLease.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845532CF2684690D00C2645D /* ParachainSlotLease.swift */; }; 845532D226846B6800C2645D /* ParachainLeaseInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845532D126846B6800C2645D /* ParachainLeaseInfo.swift */; }; 8455AB4528F7F05400974E88 /* ReferendumStatusViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8455AB4428F7F05400974E88 /* ReferendumStatusViewModelFactory.swift */; }; + 8455AB4A28F80D9300974E88 /* ReferendumTrackType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8455AB4928F80D9300974E88 /* ReferendumTrackType.swift */; }; 84563D0924F46B7F0055591D /* ManagedAccountItemMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84563D0824F46B7F0055591D /* ManagedAccountItemMapperTests.swift */; }; 8456C08227CF9DC9001282DE /* RemoteNftModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8456C08127CF9DC9001282DE /* RemoteNftModel.swift */; }; 8456C08427CFA4A7001282DE /* ImagePlaceholderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8456C08327CFA4A7001282DE /* ImagePlaceholderView.swift */; }; @@ -3717,6 +3718,7 @@ 845532CF2684690D00C2645D /* ParachainSlotLease.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParachainSlotLease.swift; sourceTree = ""; }; 845532D126846B6800C2645D /* ParachainLeaseInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParachainLeaseInfo.swift; sourceTree = ""; }; 8455AB4428F7F05400974E88 /* ReferendumStatusViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumStatusViewModelFactory.swift; sourceTree = ""; }; + 8455AB4928F80D9300974E88 /* ReferendumTrackType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumTrackType.swift; sourceTree = ""; }; 84563D0824F46B7F0055591D /* ManagedAccountItemMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedAccountItemMapperTests.swift; sourceTree = ""; }; 8456C08127CF9DC9001282DE /* RemoteNftModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteNftModel.swift; sourceTree = ""; }; 8456C08327CFA4A7001282DE /* ImagePlaceholderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePlaceholderView.swift; sourceTree = ""; }; @@ -7708,6 +7710,7 @@ 8892284928F35410003F8B9E /* ReferendumsViewModel.swift */, 88B438E628F6C629001FC08A /* StatusTimeViewModel.swift */, 8455AB4428F7F05400974E88 /* ReferendumStatusViewModelFactory.swift */, + 8455AB4928F80D9300974E88 /* ReferendumTrackType.swift */, ); path = ViewModel; sourceTree = ""; @@ -16048,6 +16051,7 @@ 97F1D128D46B072D68940FC4 /* MoonbeamTermsViewFactory.swift in Sources */, 84C5ADE8281428F1006D7388 /* WalletAccountInfoView.swift in Sources */, 849976BA27B24C2200B14A6C /* DAppBrowserTransportProtocol.swift in Sources */, + 8455AB4A28F80D9300974E88 /* ReferendumTrackType.swift in Sources */, 842822A0289BCAD300163031 /* AddAccount+ParitySignerScanWireframe.swift in Sources */, E04E3ABA985AA3D89AE20BF5 /* CrowdloanYourContributionsProtocols.swift in Sources */, 5E621A350A6DDD78597CC9E5 /* CrowdloanYourContributionsWireframe.swift in Sources */, diff --git a/novawallet/Assets.xcassets/gov/Contents.json b/novawallet/Assets.xcassets/gov/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/novawallet/Assets.xcassets/gov/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/gov/iconGovCrowdloan.imageset/Contents.json b/novawallet/Assets.xcassets/gov/iconGovCrowdloan.imageset/Contents.json new file mode 100644 index 0000000000..a31827657a --- /dev/null +++ b/novawallet/Assets.xcassets/gov/iconGovCrowdloan.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "iconGovCrowdloan.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/gov/iconGovCrowdloan.imageset/iconGovCrowdloan.pdf b/novawallet/Assets.xcassets/gov/iconGovCrowdloan.imageset/iconGovCrowdloan.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0d2ec2ee3fd90f36ce303fd280cf378767d2eb45 GIT binary patch literal 4924 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 RwI9ZC6xtCxJG*)J@-GX1hok@i literal 0 HcmV?d00001 diff --git a/novawallet/Assets.xcassets/gov/iconGovStaking.imageset/Contents.json b/novawallet/Assets.xcassets/gov/iconGovStaking.imageset/Contents.json new file mode 100644 index 0000000000..b7a1bf8b52 --- /dev/null +++ b/novawallet/Assets.xcassets/gov/iconGovStaking.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "iconGovStaking.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/gov/iconGovStaking.imageset/iconGovStaking.pdf b/novawallet/Assets.xcassets/gov/iconGovStaking.imageset/iconGovStaking.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5efa3dbe9c9f7589e27be16bdcb66ed4c1b749dc GIT binary patch literal 4825 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 RwrkpQP)Wzm&h9?n{{!h-O*sGn literal 0 HcmV?d00001 diff --git a/novawallet/Common/Extension/Foundation/NumberFormatter.swift b/novawallet/Common/Extension/Foundation/NumberFormatter.swift index 9c415359a2..7a4e8f80e0 100644 --- a/novawallet/Common/Extension/Foundation/NumberFormatter.swift +++ b/novawallet/Common/Extension/Foundation/NumberFormatter.swift @@ -71,6 +71,18 @@ extension NumberFormatter { return numberFormatter } + static var percentHalfEven: NumberFormatter { + let numberFormatter = percent + numberFormatter.roundingMode = .halfEven + return numberFormatter + } + + static var index: NumberFormatter { + let numberFormatter = quantity + numberFormatter.positivePrefix = "#" + return numberFormatter + } + static var quantity: NumberFormatter { let numberFormatter = NumberFormatter() numberFormatter.numberStyle = .decimal diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift index 7f95fa9184..71dd8d1066 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift @@ -6,7 +6,7 @@ protocol ReferendumDecidingFunctionProtocol { struct Gov2LocalDecidingFunction: ReferendumDecidingFunctionProtocol { let curve: Referenda.Curve - let startBlock: BlockNumber + let startBlock: BlockNumber? let period: Moment private func calculateLinearDecreasing(from xPoint: Decimal, params: Referenda.LinearDecreasingCurve) -> Decimal? { @@ -59,6 +59,8 @@ extension Gov2LocalDecidingFunction { func calculateThreshold(for block: BlockNumber) -> Decimal? { let xPoint: Decimal + let startBlock = self.startBlock ?? block + if block < startBlock { xPoint = 0 } else if block > startBlock + period { diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index 493485d15a..38c4aa0fed 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -47,13 +47,25 @@ final class Gov2LocalMappingFactory { track: Referenda.TrackInfo, additionalInfo: Gov2OperationFactory.AdditionalInfo ) -> ReferendumStateLocal { + let approvalFunction = Gov2LocalDecidingFunction( + curve: track.minApproval, + startBlock: nil, + period: track.decisionPeriod + ) + + let supportFunction = Gov2LocalDecidingFunction( + curve: track.minSupport, + startBlock: nil, + period: track.decisionPeriod + ) + let votes = SupportAndVotesLocal( ayes: status.tally.ayes, nays: status.tally.nays, support: status.tally.support, totalIssuance: additionalInfo.totalIssuance, - approvalFunction: nil, - supportFunction: nil + approvalFunction: approvalFunction, + supportFunction: supportFunction ) let localTrack = GovernanceTrackLocal(trackId: status.track, name: track.name) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 6ec9176104..e12b67cec5 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -102,6 +102,7 @@ final class ReferendumsPresenter { } private func invalidateTimer() { + countdownTimer?.delegate = nil countdownTimer?.stop() countdownTimer = nil } diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift index 1395236d37..f857c04f15 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -28,6 +28,8 @@ final class ReferendumInfoView: UIView { $0.titleLabel.numberOfLines = 1 } + private var trackImageViewModel: ImageViewModelProtocol? + lazy var trackInformation: UIStackView = UIView.hStack( spacing: 6, [ @@ -75,6 +77,7 @@ extension ReferendumInfoView { let time: Time? let title: String? let track: Track? + let referendumNumber: String? struct Time: Equatable { let titleIcon: TitleIconViewModel @@ -82,8 +85,8 @@ extension ReferendumInfoView { } struct Track { - let titleIcon: TitleIconViewModel - let referendumNumber: String? + let title: String + let icon: ImageViewModelProtocol? } struct Status { @@ -99,12 +102,35 @@ extension ReferendumInfoView { } func bind(viewModel: Model) { - trackInformation.isHidden = viewModel.track == nil - numberLabel.isHidden = viewModel.track?.referendumNumber == nil + trackImageViewModel?.cancel(on: trackNameView.iconDetailsView.imageView) + trackImageViewModel = viewModel.track?.icon + + if let track = viewModel.track { + trackInformation.isHidden = false + + trackNameView.iconDetailsView.detailsLabel.text = track.title + + let iconSize = trackNameView.iconDetailsView.iconWidth + let imageSettings = ImageViewModelSettings( + targetSize: CGSize(width: iconSize, height: iconSize), + cornerRadius: nil, + tintColor: UILabel.Style.track.textColor + ) + + track.icon?.loadImage( + on: trackNameView.iconDetailsView.imageView, + settings: imageSettings, + animated: true + ) + } else { + trackInformation.isHidden = true + } + + numberLabel.isHidden = viewModel.referendumNumber == nil titleLabel.text = viewModel.title - trackNameView.iconDetailsView.bind(viewModel: viewModel.track?.titleIcon) - numberLabel.titleLabel.text = viewModel.track?.referendumNumber + + numberLabel.titleLabel.text = viewModel.referendumNumber statusLabel.text = viewModel.status.name bind(timeModel: viewModel.time) @@ -166,7 +192,7 @@ extension UILabel.Style { extension RoundedView.Style { static let referendum = RoundedView.Style( fillColor: R.color.colorWhite8()!, - highlightedFillColor: R.color.colorWhite8()!, + highlightedFillColor: R.color.colorAccentSelected()!, cornerRadius: 8 ) } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTrackType.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTrackType.swift new file mode 100644 index 0000000000..5de4ad0623 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTrackType.swift @@ -0,0 +1,90 @@ +import Foundation +import UIKit + +enum ReferendumTrackType: String, CaseIterable, Equatable { + case root + case whiteListedCaller = "whitelisted_caller" + case stakingAdmin = "staking_admin" + case treasurer + case leaseAdmin = "lease_admin" + case fellowshipAdmin = "fellowship_admin" + case generalAdmin = "general_admin" + case auctionAdmin = "auction_admin" + case referendumCanceller = "referendum_canceller" + case referendumKiller = "referendum_killer" + case smallTipper = "small_tipper" + case bigTipper = "big_tipper" + case smallSpender = "small_spender" + case mediumSpender = "medium_spender" + case bigSpender = "big_spender" + + var priority: UInt { + let index = Self.allCases.firstIndex(of: self) + return UInt(index ?? 0) + } + + // swiftlint:disable:next cyclomatic_complexity + func title(for locale: Locale) -> String? { + switch self { + case .root: + return R.string.localizable.govTrackRoot(preferredLanguages: locale.rLanguages) + case .whiteListedCaller: + return R.string.localizable.govTrackWhitelistedCaller(preferredLanguages: locale.rLanguages) + case .stakingAdmin: + return R.string.localizable.govTrackStakingAdmin(preferredLanguages: locale.rLanguages) + case .treasurer: + return R.string.localizable.govTrackTreasurer(preferredLanguages: locale.rLanguages) + case .leaseAdmin: + return R.string.localizable.govTrackLeaseAdmin(preferredLanguages: locale.rLanguages) + case .fellowshipAdmin: + return R.string.localizable.govTrackFellowshipAdmin(preferredLanguages: locale.rLanguages) + case .generalAdmin: + return R.string.localizable.govTrackGeneralAdmin(preferredLanguages: locale.rLanguages) + case .auctionAdmin: + return R.string.localizable.govTrackAuctionAdmin(preferredLanguages: locale.rLanguages) + case .referendumCanceller: + return R.string.localizable.govTrackReferendumCanceller(preferredLanguages: locale.rLanguages) + case .referendumKiller: + return R.string.localizable.govTrackReferendumKiller(preferredLanguages: locale.rLanguages) + case .smallTipper: + return R.string.localizable.govTrackSmallTipper(preferredLanguages: locale.rLanguages) + case .bigTipper: + return R.string.localizable.govTrackBigTipper(preferredLanguages: locale.rLanguages) + case .smallSpender: + return R.string.localizable.govTrackSmallSpender(preferredLanguages: locale.rLanguages) + case .mediumSpender: + return R.string.localizable.govTrackMediumSpender(preferredLanguages: locale.rLanguages) + case .bigSpender: + return R.string.localizable.govTrackBigSpender(preferredLanguages: locale.rLanguages) + } + } + + func imageViewModel(for chain: ChainModel) -> ImageViewModelProtocol? { + switch self { + case .root: + return RemoteImageViewModel(url: chain.utilityAsset()?.icon ?? chain.icon) + case .whiteListedCaller, .fellowshipAdmin: + return StaticImageViewModel(image: R.image.iconGovFellowship()!) + case .auctionAdmin: + return StaticImageViewModel(image: R.image.iconGovCrowdloan()!) + case .stakingAdmin: + return StaticImageViewModel(image: R.image.iconGovStaking()!) + case .leaseAdmin, .generalAdmin, .referendumCanceller, .referendumKiller: + return StaticImageViewModel(image: R.image.iconGovGovernance()!) + case .treasurer, .smallTipper, .bigTipper, .smallSpender, .mediumSpender, .bigSpender: + return StaticImageViewModel(image: R.image.iconGovTreasury()!) + } + } + + static func createViewModel( + from rawName: String, + chain: ChainModel, + locale: Locale + ) -> ReferendumInfoView.Model.Track { + let type = ReferendumTrackType(rawValue: rawName) + let title = type?.title(for: locale)?.uppercased() ?? rawName.replacingSnakeCase().uppercased() + let icon = type?.imageViewModel(for: chain) + + return .init(title: title, icon: icon) + } +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 4cb669c2b5..9ddbb49a3f 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -33,19 +33,19 @@ final class ReferendumsModelFactory { let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol let localizedPercentFormatter: LocalizableResource - let localizedQuantityFormatter: LocalizableResource + let localizedIndexFormatter: LocalizableResource let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol init( statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol, assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, percentFormatter: LocalizableResource, - quantityNumberFormatter: LocalizableResource + indexFormatter: LocalizableResource ) { self.statusViewModelFactory = statusViewModelFactory self.assetBalanceFormatterFactory = assetBalanceFormatterFactory localizedPercentFormatter = percentFormatter - localizedQuantityFormatter = quantityNumberFormatter + localizedIndexFormatter = indexFormatter } private func provideCommonReferendumCellViewModel( @@ -58,12 +58,18 @@ final class ReferendumsModelFactory { chainAsset: params.chainInfo.chain.utilityAsset(), locale: locale ) + + let referendumNumber = localizedIndexFormatter.value(for: locale).string( + from: NSNumber(value: params.referendum.index) + ) + return .init( referendumInfo: .init( status: status, time: nil, title: params.metadata?.name ?? "", - track: nil + track: nil, + referendumNumber: referendumNumber ), progress: nil, yourVotes: yourVotesModel @@ -99,9 +105,14 @@ final class ReferendumsModelFactory { chainAsset: params.chainInfo.chain.utilityAsset(), locale: locale ) - let trackName = model.track.name.replacingSnakeCase().uppercased() - let referendumNumber = localizedQuantityFormatter.value(for: locale).string( + let track = ReferendumTrackType.createViewModel( + from: model.track.name, + chain: params.chainInfo.chain, + locale: locale + ) + + let referendumNumber = localizedIndexFormatter.value(for: locale).string( from: NSNumber(value: params.referendum.index) ) @@ -110,10 +121,8 @@ final class ReferendumsModelFactory { status: .init(name: title.uppercased(), kind: .neutral), time: timeModel?.viewModel, title: params.metadata?.name ?? "", - track: .init( - titleIcon: .init(title: trackName, icon: nil), - referendumNumber: referendumNumber.map { "#" + $0 } - ) + track: track, + referendumNumber: referendumNumber ), progress: progressViewModel, yourVotes: yourVotesModel @@ -191,20 +200,23 @@ final class ReferendumsModelFactory { chainAsset: params.chainInfo.chain.utilityAsset(), locale: locale ) - let trackName = model.track.name.replacingSnakeCase().uppercased() - let quantityFormatter = localizedQuantityFormatter.value(for: locale) - let referendumNumber = quantityFormatter.string(from: NSNumber(value: params.referendum.index)) + let track = ReferendumTrackType.createViewModel( + from: model.track.name, + chain: params.chainInfo.chain, + locale: locale + ) + + let indexFormatter = localizedIndexFormatter.value(for: locale) + let referendumNumber = indexFormatter.string(from: NSNumber(value: params.referendum.index)) return .init( referendumInfo: .init( status: .init(name: statusName.uppercased(), kind: statusKind), time: timeModel?.viewModel, title: params.metadata?.name, - track: .init( - titleIcon: .init(title: trackName, icon: nil), - referendumNumber: referendumNumber.map { "#" + $0 } - ) + track: track, + referendumNumber: referendumNumber ), progress: progressViewModel, yourVotes: yourVotesModel @@ -213,7 +225,6 @@ final class ReferendumsModelFactory { } private func provideApprovedReferendumCellViewModel( - _: ReferendumStateLocal.Approved, params: StatusParams, locale: Locale ) -> ReferendumView.Model { @@ -232,12 +243,17 @@ final class ReferendumsModelFactory { locale: locale ) + let referendumNumber = localizedIndexFormatter.value(for: locale).string( + from: NSNumber(value: params.referendum.index) + ) + return .init( referendumInfo: .init( status: .init(name: title.uppercased(), kind: .positive), time: timeModel?.viewModel, title: params.metadata?.name, - track: nil + track: nil, + referendumNumber: referendumNumber ), progress: nil, yourVotes: yourVotesModel @@ -256,10 +272,13 @@ final class ReferendumsModelFactory { return nil } - let targetThreshold = Decimal.fromSubstrateAmount( + let totalIssuanceDecimal = Decimal.fromSubstrateAmount( supportAndVotes.totalIssuance, precision: Int16(chainAsset.precision) - ) + ) ?? 0 + + let targetThreshold = totalIssuanceDecimal * supportThreshold + let threshold = Decimal.fromSubstrateAmount( supportAndVotes.support, precision: Int16(chainAsset.precision) @@ -267,15 +286,13 @@ final class ReferendumsModelFactory { let isCompleted = supportAndVotes.supportFraction >= supportThreshold let image = isCompleted ? - R.image.iconCheckmark()?.withTintColor(R.color.colorGreen15CF37()!) : - R.image.iconClose()?.withTintColor(R.color.colorRedFF3A69()!) + R.image.iconCheckmark()?.tinted(with: R.color.colorGreen15CF37()!) : + R.image.iconClose()?.tinted(with: R.color.colorRedFF3A69()!) let tokenFormatter = assetBalanceFormatterFactory.createTokenFormatter(for: chainAsset.displayInfo) let amountFormatter = assetBalanceFormatterFactory.createDisplayFormatter(for: chainAsset.displayInfo) - let targetThresholdString = targetThreshold.map { - tokenFormatter.value(for: locale).stringFromDecimal($0) ?? "" - } ?? "" + let targetThresholdString = tokenFormatter.value(for: locale).stringFromDecimal(targetThreshold) ?? "" let thresholdString = threshold.map { amountFormatter.value(for: locale).stringFromDecimal($0) ?? "" @@ -390,8 +407,8 @@ extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { return providePreparingReferendumCellViewModel(model, params: params, locale: locale) case let .deciding(model): return provideDecidingReferendumCellViewModel(model, params: params, locale: locale) - case let .approved(model): - return provideApprovedReferendumCellViewModel(model, params: params, locale: locale) + case .approved: + return provideApprovedReferendumCellViewModel(params: params, locale: locale) case .rejected: let statusName = Strings.governanceReferendumsStatusRejected(preferredLanguages: locale.rLanguages) status = .init(name: statusName, kind: .negative) diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index 87bb5fc930..a43878814c 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -183,16 +183,13 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { let interactor = createGovernanceInteractor(for: state, wallet: wallet) let wireframe = ReferendumsWireframe() - let percentFormatter = NumberFormatter.percent - percentFormatter.roundingMode = .halfEven - let statusViewModelFactory = ReferendumStatusViewModelFactory() let viewModelFactory = ReferendumsModelFactory( statusViewModelFactory: statusViewModelFactory, assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), - percentFormatter: percentFormatter.localizableResource(), - quantityNumberFormatter: NumberFormatter.quantity.localizableResource() + percentFormatter: NumberFormatter.percentHalfEven.localizableResource(), + indexFormatter: NumberFormatter.index.localizableResource() ) let presenter = ReferendumsPresenter( diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index f998feff01..1d75d30d38 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1006,3 +1006,18 @@ "governance.to.pass.format" = "To pass: %@"; "governance.aye" = "Aye"; "governance.nay" = "Nay"; +"gov.track.root" = "Root"; +"gov.track.auction.admin" = "Crowdloans"; +"gov.track.staking.admin" = "Staking"; +"gov.track.lease.admin" = "Governance: Lease"; +"gov.track.general.admin" = "Governance: Registrar"; +"gov.track.referendum.canceller" = "Governance: Canceller"; +"gov.track.referendum.killer" = "Governance: Killer"; +"gov.track.treasurer" = "Treasury: Any"; +"gov.track.small.tipper" = "Treasury: Small tips"; +"gov.track.big.tipper" = "Treasury: Big tips"; +"gov.track.small.spender" = "Treasury: Small Spend"; +"gov.track.medium.spender" = "Treasury: Medium Spend"; +"gov.track.big.spender" = "Treasury: Big Spend"; +"gov.track.whitelisted.caller" = "Fellowship: Whitelist"; +"gov.track.fellowship.admin" = "Fellowship: Admin"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 989ab9a5d2..d5905d9061 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1007,3 +1007,18 @@ "governance.to.pass.format" = "Для одобрения: %@"; "governance.aye" = "За"; "governance.nay" = "Против"; +"gov.track.root" = "Root"; +"gov.track.auction.admin" = "Crowdloans"; +"gov.track.staking.admin" = "Staking"; +"gov.track.lease.admin" = "Governance: Lease"; +"gov.track.general.admin" = "Governance: Registrar"; +"gov.track.referendum.canceller" = "Governance: Canceller"; +"gov.track.referendum.killer" = "Governance: Killer"; +"gov.track.treasurer" = "Treasury: Any"; +"gov.track.small.tipper" = "Treasury: Small tips"; +"gov.track.big.tipper" = "Treasury: Big tips"; +"gov.track.small.spender" = "Treasury: Small Spend"; +"gov.track.medium.spender" = "Treasury: Medium Spend"; +"gov.track.big.spender" = "Treasury: Big Spend"; +"gov.track.whitelisted.caller" = "Fellowship: Whitelist"; +"gov.track.fellowship.admin" = "Fellowship: Admin"; From 58780100e06848f4545af17b4a46657824cc2ebc Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 13 Oct 2022 18:07:48 +0500 Subject: [PATCH 038/229] fix localization --- novawallet/en.lproj/Localizable.strings | 2 +- novawallet/ru.lproj/Localizable.strings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 1d75d30d38..714ecdbb0f 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1006,7 +1006,7 @@ "governance.to.pass.format" = "To pass: %@"; "governance.aye" = "Aye"; "governance.nay" = "Nay"; -"gov.track.root" = "Root"; +"gov.track.root" = "Main agenda"; "gov.track.auction.admin" = "Crowdloans"; "gov.track.staking.admin" = "Staking"; "gov.track.lease.admin" = "Governance: Lease"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index d5905d9061..382af2c298 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1007,7 +1007,7 @@ "governance.to.pass.format" = "Для одобрения: %@"; "governance.aye" = "За"; "governance.nay" = "Против"; -"gov.track.root" = "Root"; +"gov.track.root" = "Main agenda"; "gov.track.auction.admin" = "Crowdloans"; "gov.track.staking.admin" = "Staking"; "gov.track.lease.admin" = "Governance: Lease"; From d63fce4d049dc859a832c7f7a5c03bbe6f7fa9e9 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 13 Oct 2022 20:19:38 +0400 Subject: [PATCH 039/229] fix layout, dotted view --- Podfile.lock | 12 +- novawallet.xcodeproj/project.pbxproj | 12 +- .../Common/View/Chart/FWBarChartView.swift | 2 +- .../Common/View/Chart/FWLineChartView.swift | 6 +- .../Chart/FWXAxisEmptyValueFormatter.swift | 2 +- .../MyPlayground.playground/Contents.swift | 68 +++++++++++ .../Resources/PublicSans-Bold.otf | Bin 0 -> 56032 bytes .../Resources/PublicSans-ExtraBold.otf | Bin 0 -> 56468 bytes .../Resources/PublicSans-ExtraLight.otf | Bin 0 -> 56584 bytes .../Resources/PublicSans-Medium.otf | Bin 0 -> 56180 bytes .../Resources/PublicSans-Regular.otf | Bin 0 -> 56792 bytes .../Resources/PublicSans-SemiBold.otf | Bin 0 -> 56720 bytes .../contents.xcplayground | 4 + .../timeline.xctimeline | 6 + .../View/ReferendumTimelineView.swift | 103 ++++++++++++++++ .../ReferendumVotingStatusDetailsView.swift | 48 ++++++-- .../View/ReferendumVotingStatusView.swift | 20 +-- .../ReferendumDetails/View/VoteRowView.swift | 114 ++++++++++++++++++ 18 files changed, 369 insertions(+), 28 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Bold.otf create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraBold.otf create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraLight.otf create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Medium.otf create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Regular.otf create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-SemiBold.otf create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/contents.xcplayground create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/timeline.xctimeline create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift diff --git a/Podfile.lock b/Podfile.lock index d0eec8b5d8..dc096ffed9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,8 +1,9 @@ PODS: - BigInt (5.2.0) - - Charts (3.6.0): - - Charts/Core (= 3.6.0) - - Charts/Core (3.6.0) + - Charts (4.1.0): + - Charts/Core (= 4.1.0) + - Charts/Core (4.1.0): + - SwiftAlgorithms (~> 1.0) - CocoaLumberjack (3.7.2): - CocoaLumberjack/Core (= 3.7.2) - CocoaLumberjack/Core (3.7.2) @@ -114,6 +115,7 @@ PODS: - xxHash-Swift (~> 1.0.0) - SVGKit (2.1.0): - CocoaLumberjack (~> 3.0) + - SwiftAlgorithms (1.0.0) - SwiftFormat/CLI (0.47.13) - SwiftLint (0.43.1) - SwiftRLP (1.1): @@ -164,6 +166,7 @@ SPEC REPOS: - SoraFoundation - SoraKeystore - Sourcery + - SwiftAlgorithms - SwiftFormat - SwiftLint - SwiftyBeaver @@ -211,7 +214,7 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: BigInt: f668a80089607f521586bbe29513d708491ef2f7 - Charts: b1e3a1f5a1c9ba5394438ca3b91bd8c9076310af + Charts: 354f86803d11d9c35de280587fef50d1af063978 CocoaLumberjack: b7e05132ff94f6ae4dfa9d5bce9141893a21d9da CommonWallet: 59fdbf5511d6fcdc38496db4baf425dd0cf29274 Cuckoo: 9e258d68137c411df47c6390f72901d5276b4f03 @@ -233,6 +236,7 @@ SPEC CHECKSUMS: Starscream: 8cc648110705c09a15f0de84352c7f9595b7cb05 SubstrateSdk: 8a3e490b078413fc444706899c751766a22c7821 SVGKit: 132b010efbf57ec345309fe4a7f627c0a40c5d63 + SwiftAlgorithms: 38dda4731d19027fdeee1125f973111bf3386b53 SwiftFormat: 73573b89257437c550b03d934889725fbf8f75e5 SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 SwiftRLP: f58417bfceecd45394fc619ccad14cf16e4ae6c1 diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 5e7e41877a..887b08b75c 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2232,6 +2232,7 @@ 88A5318028B9328E00AF18F5 /* YourWalletsViewSectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A5317F28B9328E00AF18F5 /* YourWalletsViewSectionModel.swift */; }; 88A6BCFF28CA15400047E4C2 /* LocksBalanceViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A6BCFE28CA15400047E4C2 /* LocksBalanceViewModelFactory.swift */; }; 88A6BD0128CA15710047E4C2 /* LocksViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A6BD0028CA15710047E4C2 /* LocksViewInput.swift */; }; + 88A95FA628F8664100BE26F3 /* ReferendumTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A95FA528F8664100BE26F3 /* ReferendumTimelineView.swift */; }; 88AA0FB828B60E6A00931800 /* YourWalletsControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AA0FB728B60E6A00931800 /* YourWalletsControlView.swift */; }; 88AC186128CA3EE100892A9B /* LocksViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AC186028CA3EE100892A9B /* LocksViewLayout.swift */; }; 88AC186328CA3F0000892A9B /* GenericCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AC186228CA3F0000892A9B /* GenericCollectionViewLayout.swift */; }; @@ -2239,6 +2240,7 @@ 88AF35DE28C21D28003730DA /* LocksSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AF35DD28C21D28003730DA /* LocksSubscription.swift */; }; 88B1862A28EF30A600D49854 /* YourVoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B1862928EF30A600D49854 /* YourVoteView.swift */; }; 88B438E728F6C629001FC08A /* StatusTimeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B438E628F6C629001FC08A /* StatusTimeModel.swift */; }; + 88B560BC28F80DCB00A5EB59 /* VoteRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */; }; 88BB21A028D34C660019C6B4 /* DataProviderChange+Identifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88BB219F28D34C660019C6B4 /* DataProviderChange+Identifier.swift */; }; 88C017E628C60A65003B2D28 /* AssetLockMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C017E528C60A65003B2D28 /* AssetLockMapper.swift */; }; 88C7165428C894510015D1E9 /* CollectionViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C7165328C894510015D1E9 /* CollectionViewDelegate.swift */; }; @@ -5070,6 +5072,7 @@ 88A5317F28B9328E00AF18F5 /* YourWalletsViewSectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsViewSectionModel.swift; sourceTree = ""; }; 88A6BCFE28CA15400047E4C2 /* LocksBalanceViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksBalanceViewModelFactory.swift; sourceTree = ""; }; 88A6BD0028CA15710047E4C2 /* LocksViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksViewInput.swift; sourceTree = ""; }; + 88A95FA528F8664100BE26F3 /* ReferendumTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumTimelineView.swift; sourceTree = ""; }; 88AA0FB728B60E6A00931800 /* YourWalletsControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsControlView.swift; sourceTree = ""; }; 88AC186028CA3EE100892A9B /* LocksViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksViewLayout.swift; sourceTree = ""; }; 88AC186228CA3F0000892A9B /* GenericCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericCollectionViewLayout.swift; sourceTree = ""; }; @@ -5077,6 +5080,8 @@ 88AF35DD28C21D28003730DA /* LocksSubscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksSubscription.swift; sourceTree = ""; }; 88B1862928EF30A600D49854 /* YourVoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourVoteView.swift; sourceTree = ""; }; 88B438E628F6C629001FC08A /* StatusTimeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTimeModel.swift; sourceTree = ""; }; + 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteRowView.swift; sourceTree = ""; }; + 88B560BD28F831CC00A5EB59 /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 88BB219F28D34C660019C6B4 /* DataProviderChange+Identifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataProviderChange+Identifier.swift"; sourceTree = ""; }; 88C017E528C60A65003B2D28 /* AssetLockMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetLockMapper.swift; sourceTree = ""; }; 88C7165328C894510015D1E9 /* CollectionViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewDelegate.swift; sourceTree = ""; }; @@ -11909,8 +11914,11 @@ 888A3B6328F73B9200E15BD2 /* View */ = { isa = PBXGroup; children = ( - 888A3B6428F73DC300E15BD2 /* ReferendumVotingStatusView.swift */, + 88A95FA528F8664100BE26F3 /* ReferendumTimelineView.swift */, 888A3B6628F746D200E15BD2 /* ReferendumVotingStatusDetailsView.swift */, + 888A3B6428F73DC300E15BD2 /* ReferendumVotingStatusView.swift */, + 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */, + 88B560BD28F831CC00A5EB59 /* MyPlayground.playground */, ); path = View; sourceTree = ""; @@ -14404,6 +14412,7 @@ 848F8B1928635A5600204BC4 /* TransferSetupPresenter.swift in Sources */, 841221A028F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift in Sources */, 84100F3626A6069200A5054E /* IconTitleValueView.swift in Sources */, + 88B560BC28F80DCB00A5EB59 /* VoteRowView.swift in Sources */, 842876AB24AE049B00D91AD8 /* SelectionItemViewProtocol.swift in Sources */, 8472C5AF265CF9C500E2481B /* StakingRewardDestConfirmViewLayout.swift in Sources */, 84796080283B63240084E779 /* LoadableActionView.swift in Sources */, @@ -15866,6 +15875,7 @@ 0FB6781AB0186A1ED474CAD6 /* StakingUnbondConfirmProtocols.swift in Sources */, 8401AEC52642A71D000B03E3 /* StakingRebondConfirmationViewFactory.swift in Sources */, 27FA1D57A06AA3A030D226B6 /* StakingUnbondConfirmWireframe.swift in Sources */, + 88A95FA628F8664100BE26F3 /* ReferendumTimelineView.swift in Sources */, 843A2C7326A8641400266F53 /* MultiValueView.swift in Sources */, 3FF8EE1158A273D0D50BC7A6 /* StakingUnbondConfirmPresenter.swift in Sources */, F0C3DB0CEE1975626B0014A8 /* StakingUnbondConfirmInteractor.swift in Sources */, diff --git a/novawallet/Common/View/Chart/FWBarChartView.swift b/novawallet/Common/View/Chart/FWBarChartView.swift index 6689586fdb..f23e694973 100644 --- a/novawallet/Common/View/Chart/FWBarChartView.swift +++ b/novawallet/Common/View/Chart/FWBarChartView.swift @@ -33,7 +33,7 @@ final class FWBarChartView: BarChartView { delegate = self backgroundColor = .clear - chartDescription?.enabled = false + chartDescription.enabled = false autoScaleMinMaxEnabled = true doubleTapToZoomEnabled = false diff --git a/novawallet/Common/View/Chart/FWLineChartView.swift b/novawallet/Common/View/Chart/FWLineChartView.swift index 913db917c8..a4e1636ecd 100644 --- a/novawallet/Common/View/Chart/FWLineChartView.swift +++ b/novawallet/Common/View/Chart/FWLineChartView.swift @@ -13,7 +13,7 @@ final class FWLineChartView: LineChartView { delegate = self backgroundColor = .clear - chartDescription?.enabled = false + chartDescription.enabled = false autoScaleMinMaxEnabled = true doubleTapToZoomEnabled = false @@ -97,7 +97,7 @@ extension FWLineChartView: FWChartViewProtocol { } } - func createDataSet(dataEntries: [ChartDataEntry]) -> IChartDataSet { + func createDataSet(dataEntries: [ChartDataEntry]) -> ChartDataSet { let dataSet = LineChartDataSet(entries: dataEntries) dataSet.mode = .horizontalBezier dataSet.drawIconsEnabled = false @@ -114,7 +114,7 @@ extension FWLineChartView: FWChartViewProtocol { colors: gradientColors, locations: colorLocations )! - dataSet.fill = Fill(linearGradient: linearGradient, angle: 90) + dataSet.fill = LinearGradientFill(gradient: linearGradient, angle: 90) dataSet.fillAlpha = 1.0 dataSet.drawFilledEnabled = true dataSet.highlightColor = R.color.colorGreen()! diff --git a/novawallet/Common/View/Chart/FWXAxisEmptyValueFormatter.swift b/novawallet/Common/View/Chart/FWXAxisEmptyValueFormatter.swift index 2cd89f965c..2576035eba 100644 --- a/novawallet/Common/View/Chart/FWXAxisEmptyValueFormatter.swift +++ b/novawallet/Common/View/Chart/FWXAxisEmptyValueFormatter.swift @@ -2,7 +2,7 @@ import Charts /// `FWXAxisEmptyValueFormatter` returns empty string and thus own place /// under chart thas is used by `FWXAxisChartLegendView` -final class FWXAxisEmptyValueFormatter: IAxisValueFormatter { +final class FWXAxisEmptyValueFormatter: AxisValueFormatter { func stringForValue(_: Double, axis _: AxisBase?) -> String { "" } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift new file mode 100644 index 0000000000..4db8baec43 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift @@ -0,0 +1,68 @@ +//: A UIKit based Playground for presenting user interface + +import UIKit +import SnapKit +import PlaygroundSupport + +private func registerFonts() { + registerFont(name: "PublicSans-Medium") + registerFont(name: "PublicSans-ExtraLight") + registerFont(name: "PublicSans-SemiBold") + registerFont(name: "PublicSans-Regular") + registerFont(name: "PublicSans-ExtraBold") + registerFont(name: "PublicSans-Bold") +} + +private func registerFont(name: String) { + let cfURL = Bundle.main.url( + forResource: name, + withExtension: "otf" + )! as CFURL + + CTFontManagerRegisterFontsForURL(cfURL, CTFontManagerScope.process, nil) +} + +registerFonts() +let view = UIView() +view.backgroundColor = .black +view.frame = .init( + origin: .zero, + size: .init(width: 360, height: 800) +) + +var detailsView = ReferendumVotingStatusDetailsView() +view.addSubview(detailsView) +detailsView.snp.makeConstraints { + $0.centerY.equalToSuperview() + $0.leading.trailing.equalToSuperview() +} + +let status = ReferendumVotingStatusView.Model( + status: .init(name: "PASSING", kind: .positive), + time: .init(titleIcon: .init(title: "Approve in 03:59:59", icon: R.image.iconFire()), isUrgent: true), + title: "Voting status" +) +let votingProgress = VotingProgressView.Model( + ayeProgress: "Aye: 99.9%", + passProgress: "To pass: 50%", + nayProgress: "Nay: 0.1%", + thresholdModel: .init(titleIcon: .init(title: "Threshold reached", icon: R.image.iconCheckmark()?.withTintColor(R.color.colorDarkGreen()!)), value: 0.5), + progress: 0.9 +) +detailsView.bind(viewModel: .init( + status: status, + votingProgress: votingProgress, + aye: .init( + title: "Aye", + votes: "25,354.16 votes", + tokens: "16,492 KSM" + ), + nay: .init( + title: "Nay", + votes: "1.5 votes", + tokens: "149 KSM" + ), + buttonText: "Vote" +)) + +PlaygroundPage.current.liveView = view diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Bold.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Bold.otf new file mode 100644 index 0000000000000000000000000000000000000000..7a2b62bd49a8a1aabae8c5b5847eb71bd977ee4f GIT binary patch literal 56032 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 Mdo71h?`WI+A3W~&d;kCd literal 0 HcmV?d00001 diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraBold.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraBold.otf new file mode 100644 index 0000000000000000000000000000000000000000..09b52ddfe78a6ca5e566789dced5cff293d615f1 GIT binary patch literal 56468 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 be?C_L5E{okKmOdzz~3hWO5sfJZIk~8Y0T9n literal 0 HcmV?d00001 diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraLight.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraLight.otf new file mode 100644 index 0000000000000000000000000000000000000000..49b407d8d058bccba659c9e475af331f67b259d2 GIT binary patch literal 56584 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 literal 0 HcmV?d00001 diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Regular.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..d2b3f169a07a8ed7d29639ca8ee73415daa56159 GIT binary patch literal 56792 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 literal 0 HcmV?d00001 diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-SemiBold.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-SemiBold.otf new file mode 100644 index 0000000000000000000000000000000000000000..4ab6b8904b60bbee889093bba69374c76a52e2d5 GIT binary patch literal 56720 zcmce<2V7J~^glZH?%uo0U0g+7gxzHq6gwgvJ0L|tgQ(bJp@}F0p@_YAz^;k0Yb-IA z6pb2dG%<-rqb9K>)+DBAswU^|&O+Xqdl%FszxR9Z|3055VW*!tbLPyMneUk;ebUqW zka}b$(U7$Gq$K}iectOwNQ3o+%xRm@Ke-1Xgd^nELJaji5)zZzh6lO`S@|)huk=Xk z)BoMib_^tB71obh)1&`@?(MG3I84a-2&^8~r+@pf<(IPeAc5N|(V&@b9oBD*>A*4LOD8`1?W;9}d_D%-_>a$+Si~<( z!y>K&euxDb<8$PmVaOx58T*@GR9I44vz$~S|5LHtpK(rjLdu4%Ts*RVmp_R{cL{UI zR}o+07;#iP8a${uR^#s>>nC7RWObE)*iM&U(+&H~sX68<^pF)w?m`yuD33JdlW4V- z{9qywA~e>%iA8JFkUvH$`TS>^kj;er9ZUR&)#j!4NlhfD2%)^%mxqD-6qT0 z%)RK2OT@{iyW^f@vL@9Xug4c@K6b~A++?wXJKlhJ>)v+9y+{My$0VKttc7Kgl2kq(sRt#`a^ePL|R#4(pX-n?j_= z%3CQEOR$J{b3FDKdf*&gdY?W-N;sC~8mA9?7Hy^lw# z-H}#4(&&fjT%?hYEsJq1!8jWB)0w1_KKPr6v1i9qJDPSluIDKY#55a69#SsA(LAN~ z|E&H0CcPr0{;c#ekn88AHvqZskH7w85b~0VVFHGXqg;if{y1|b*oN`lTB+9?%QBHJ zo3$hine@gfGsi}d{Y>i|O!;HoN%)zD_1OFtVmujX6=6ExEx|m@V^mn}epn+Lsj~iA z-6Z5V2g@ca_4BYS1G#usI?rlL9`ee1%)n6XU6t$q9nV47q8#;wY2Fx&t28n&#>SY3 zeY4RQBgZUVinL2HSEXCabq<-RjEL!MZCN21jWn3FnWREVNBj-L*bCUU7=P4$*!Y+n zSP%ZFVQj3WjJm(CGL|ewMkNZ}EF3voKhJ9Wv+^!^X0C!!QcQ+yEig$3EApIxebn+? zOG#Zd1Rn-W!hPsZ~SZe2?4C9PfHp*I= z^hZtTjp;rpJ64y?b}eN#V_8Zrqrm3qpKB!)xn;kq4f(HrpU&k34 zd@y;ie&a}AC0>eF#Q$GXEf|CYu7seNtlUjLaWukqNIYE_Cc)f@F79<637$|ez|I36X!tkVB? z?f5^L%Pj1l?Gn$=IomZdQ1&^fZ2wTD8p>h73W5^^GIX1<13+7jKy#jo*qTaC3uc(kCtyb z7s~bIrgKZV72Fo?P3{ZsA#dTM`62u<{v-aDMyv7E)YmlBSTxNvtu&`>^=!>;iMC<3 zEZcb7Jljf}!@se=+27{h)W3y)h<_*l1pgxcN&Z{>U-RGL|GNJk|MvnK1vClp4`>?D zA|O3rL{q-0*tCArhD}XP%}s4h+cxdlbX3!v=I1E?_ut49rP}d7r~_{Ty5s| zBUe9hPKB$Z{8|3GhG<0O%1hy@1#;zS3$!KJhT1Z1`L>z16}HX(jr@K5t^WQBR~;3u zN|CE=3RiFVA3?6X-CXq#7=~O4$dwmz7ePP>7wbTiPd!1^wy+etr{(_6>DoeA8MXpIsQKV zr}+tU+`nqB276`ycmwx6@4@}Td+`Z;PhR34b5FRR`L^6QoP)d1{mOmIeaDCK?fFpd zN4^J+!Akr{Gdv}B!S&f4t#mr>BZJ8ZT(hH5!gI+yyc?_{uaf=bO>&UDOHOdW{l>|B zN3NPLB4@~La)*3Jej4 zd>Z!`YLO@R18?Nbd;{Lf_vKUg0=^fwgctY@sAIkPiF_YElKYIi#J|MH^U1g#CUF}&E4Q`aX*oUxVk)uFKIxU5Hsp)6rR6=NH|)_9%vbRkw9ffU>0E}DdO9a>0}F8 zM>dd67eIz`{^UijDH+Z+Bcr$$B$I1JGPsr`n`=X+a^1-oE|^TlyW=db2bs_H zCJVV#vVePmRB`>uGHxJQ$_*e(xODO|H=L}&Tg+;17}>{_kvF(vvYyK%d%05bI#+}` zT|(aGCXvJ34042=7{~>pC1=s@eoS=a6QU>Q@DBPB-m-v1 z69?`;)ubKy747lwX#4)av(sbT%YGw$xJKj!&WpUnMUxV)BN@wukbEwTjOW5h0T)5W zaiOG)>rBeIu4E$DjZETV$ONtn+Rj|EmCGZqapTAiZamq^6_8zAA=%F5lcU^h@*X#f z9OLGY2Bp{uu=&?fU18&+A^8pUv`<9mk2|1m`&ENgStm$NL(W=&1pJ zPpxe;8Cg-GetPQYbyuk$As#Y*=qCvH*=TJ2qZs7wYlxrTkG!~@*bmCli0i|6`98qr)gv>d&;LEH#jZR5Byv>S7{#oTi46>cNuwc+(+C6?sM)YcMoma zPu%aEj1m<2dVFKtIh*n=`CvYh?}D}?1@&tLYEeFF*ED_(znEXnzrt_gxAS}X!~99y z$u97h`D^@b{yY8={|E2DeNBh^Z6l3Y6M(yId$iQ?niNf6%|OkInoP}j%>>O<%>vC5 z%__}0%~s7W&D)wInvpNNd&xXj^I9YddOVwMp9E z+Ckb3ZLW5_wp2S=J5#$ryF|NMyI#9ZyIXredsKT``-%3F_L}y#_B-uE?O)nzK_?gl zZ^2J!CbSX4g-$}8&{OCm3>01zvV;PmOqeAs5UPY#!Yjf?;Wgn6;celda8x)gd?H*D zt_in=?}SIfV?h@F7Dch1*jTiPt;F_Xl-O15DW;0);xI8&%oB^m3F35dk+@8JSzIS> z5qF9E#dpPH;u-Orcv-wI-V(nRABum74js|e(>2yvbWL?Fb?tQFx^B82x)*eVbt82- zx_n)UZjx?}Zn18eZjJ60-DcfR-9FtR-AUa?x{JDNy1Tj`bieBU)KR@gFX_GXP4sqs zOMS3DS|6kDq3^37s?XAo)0gRI=ojjj>(}bH=-<#E&>z=-sQ*lVLw{fYQ2$s@Jp>P< zM-vabM{AF8k1ihZ9w{DuJqCM>^cd|i-lNoGipOk^B_69i)_ZLC*z0k?gGvUev1E~&N^PZZsgsl-rAkAjkp9qS82;?`JmL9C zTxN03gq*U1ywJqBL?!4Rr3N8t5T*tZN)YD`;?W0io+lzEJSS==MGqN%nXYg zpOIBuSP)m3TUd}YF0MGQAU7kctTZPsQ3>MJ&#Vlr6Q7k=oK-e{bbijn`0T>cjI6Aj zg3<(~C;@3?lq%hY#3w4OCn^O>R(Ev(@hV&KDhKiE0OA?v$VfzD9Z9u~%6xY>^HGT^ zpNT4;YL)mNN>4qW^2KO{hK2R0qt!DrqqygD<)MjT5y`c}#g029*Hu=i#-7}94<8BS?& z+4%g7GB!gQj=RQ8Gs1w4eIT z^nYF)VWH|Uq7)qq?U0m?laT(DrkWoXs{=U9dnfqbDy%u z@%NbsI#5G3T>~p*l=P z7pJZ8>4Gj+_$_|QZ=~9JsLEfYI!&SBB}%;#_ku2YUNm8$>M)|hOL0C*pAw5wwJ}uX zH!7j5RsbQPit)k)tqwWS9YmMa4Kh)snWQq3=pM2<*2JW;e+@D;y39RDw<OmCvHQ z$vMS^!G$HGakFGWX}OXr9fOL)(xVH@ij^>Lf|4%Do5+$SxRn>MNKRhvm{Jxg$WsX@ z^hyhg1EvQUuzd!Dj-zqul;#x{1ZU*4Z4)(FX&f3EQIu1hSD1~n zkySW;d z>d1~$3f26=0w(X$jN(a{&Mw3)wpfW2#sEc*PSV?J4 zaXu~=j7~yDR4b{gIt&L^P*|GtQdvemn!gOJsl@YhN=lSSMp035;Y1~xGrp*FQb|r} zUcue*#kr6px3945fx3^b=1`9)|s@-p(X^G2)k z>K>V2I2ny5JL86h;_6lcRmPzTt$T|OjC-BQ9s*aU@yheRt&7^fgpS+^{r z7APhyJS4t$BEmzI$;TYEoYBViaf<19+ALyBVd1!p%)$vdPxF|`4GC9lB?c;)(C%m< zGIR0^%j@bXLk|fLQ%q}kScf{!f(tT=iwjlr#A>_KPs=Cd;ViS`wo=McZXS_AW*9Mu z!e2!WYE;?S)F_h`7UE%`wl0gh>$0f3E{iI4LqbBrf>K|8DinhAMe@tm#dyqJeI8 z4K>qmz>6+KmN=V%T4>fHJJnHtN~pih2u8V!Nq()e0#aPBEf$QM_t`+No0vCj!V8xE z#aoUT22$-ddv$MW5*?|P0yPI`J*FuEqBii@3nJ6FPp zfsU#`E(2+62o&f5Ok3{IXbTOaew}E@Si8a5n9diggKHWKG|LgGGe9uxG($S|0T0^! zsLc>fTWz&L#mYr6lD2_ZgZ&2BOjHWH3u7SXo1Y9;?Rhx~3Ts@nP#%cnMX*9hqPN~hb+-xI}83aq#~dC2w{_Y8bs(0+Fzj4E;~d! zqYc8edCL~QY5~KdBZULZ1`feq@&@4+2xJf8ssvPU_7G(s;Z|u7>Ed1?h?tYbgu}Nw z%{cB=j=V*<^&CROxEQ#NJmSOTZGzq&@($s)3FH7lYzqN0?hP$z$#HLLaQ$!xcm&oE zb>|KdM6Ee|CUlr^M>s@exuaS{letp_F>mgDg2*LzTEj5GV2(ShCGQc$Fv(HEohJyn zai0q0IN`1kT!Y-_5~(8GZ9+~GMCK5-Lrk26aoimNVQTI>LQWCxffiv=?x7Yzb@D#p zej|w5alaG9`?)^|;^y3APZEtdwuW@%5CZ451c6mv&>)D)oL4Gt6B!!UW_}Yo^T?s<^d^dv7FCW7pz{tmG(G9>Sap*wh zdvXX&@+lg!f{;{>Pt_uNkIy6!yXX58^Z@Yb0%F>|WJ>O(2 zK}?>{6%gCx$Kx|7!WU@BYJv_+zF3Pc6ZC`d(Wj3fIKCai#~FxX<7A@W7A-e_lS8Y`1tHptPqYaCHHV%Q{b=X9tgSP`xGRP zJ`#kC(Jze7CH5|BJJE22-~!n~$Z$e76Ag~8h|_3%$Q*+1C-i8L`2;;T2qGhrjP5A( zG@wfgHx!N4lV8a8nN)l(Fd9d&6bYUt)#!c-LRZZQZYH;b`xG5Tzi=+xQCjjb=uq0g z-#~|DQv`K8XZ)`bbg%1< z>u&3QLZCB1-&)^U-wi>|6n(aSyncdyo_?SHmi{~aUmlW&k4H;{E@ydEB53)Z$3>6F zQa!1alqeNSbES3C9_g6$x%9R46M~JQh9tuf!*s)1!*0V91ND?V?Vfp_uX*0Dms)Q? zy_|X_^`_QaQt#z@yX&2*cgv_Z#u>AXGmNhqpBSs_2h)2KnCmW`4d}c{qldDZ0`FQvQ_(b}Q_L<HFCCZ?n!EW{x-aH4iXnnx~qVn75hVHh*lsY5vAsZSl0Uwsf)NS*BRt zv>divv|P5_v}&y$R-3hhwY#;Sb(Qr8>o3-7KgloNFU@bO-&=l1{m%J)?e`E}?M-c+ zY$MUlzQ(r4cFcC(cE|R;?TNj)J@Up)>B*0 zY(2mA%dOY7ey#P+)_YpN)%tXsgf>0fq_!E^CaX<;o5D6_ZC+`!yUibMz1lWuJFe}T zw(qw6vu$;d7*sFFC&)jjRZvJ!hoGdO)Sv-D!-KMd#s`%KO$nMEv?ypz(1xJxLHmLZ z2AvA}IOtN)^`N^!zXbgiRMSq^&e+bkT|m3m?LymiY}cb*pLW^p#p?`<@gr$Wo2>T(t zM|fuV%<#G43&Yoj?+rg5{#p3d@Fx+05#1w(MPx?IiC7h}A>wevjfjU4zeM~V@gy=j z@}sESsPChDMbD1j8GW^bp@V;iH66a~XzBQV$6q_eb-LWSZ|8%Zf9}$#OJbL)T~>6t z*VWuLxoc+E30+_9y0z=ou77nibW7`2(5<4|zHT>SJYw==HpLu_xfVM(_V>7?xb1Og z;=b)Jbr0>nyZgQFkK>c#UrK17a4)ez;^`#Mq(w=`lYZ$D(j&IVupZ}nJn0$Lb7Ifx zYWiL#|W!qflwVL=FM8W-EM?6pLq{OD})h;CQ$O1s;jK>i8c}@Gp(Ynl@udY z+pLcJN{-E{>##-Y>Uu-T4yet3uA+%iqu&*7znUijN&AjA+&ofxZMNh(K;P;vbw*#4>vC-mNmkv23DWMj?0L!^ z=AbmyRn$|0g#wKcT^DL=oFG-;!oXlO+13J42nHI*CewQlvz8)z;o) z75$!PrMk7%F`ErtZekS^qx>LJgmz;)`_a#>j-yJx)hdphBhl+t2Vv>YykU_D-tf14 zq5@3xZ{dJQy@!rTOEd>wO#}1Yo7?bGaY_2{y#wHT(!Q)ptg2jC;d<37Y!m2uF|ry= zP~b4Y_-cc|v?$vuHZp{Bb?czF$JiiXe=9$lUrnFuQSN0G(*{eg ze<0C2R!7@5lH=SLPnaG`kO1-C@>)@D1U;c4tcO;8A&}1azz*qG zFZ>Cu%&?FqgW09Ax#o$mz~wT@ongBUV!@a|o6{g_Pp7_idbGNMN$v$lbwBu@D95hz9I%#<=sl2pH;NKE76e^6D9c7DqmMJM}H#idjQ{W z!OPWz-LS;>N6FO-#?k#yQ)o}6{=zY&CR>@R!pI7`tf};kRldPm%5<9q^;Oz4aaciq z@8KHW1BDp-NrIWObB#okt@0z&KTF(|-*Vjumab#seaU!TKEnj%x{q=Sm99IQx>vrd z1eZ8w$QO~A9}>ejTwvTxmR$a*!L0Hh&n&Q~+0Ruoy)Vf=Z%WslssFjOp0>i(%2w8S z>66Om7gYHOI$NaGYNjFt zg+cioTU|&?5ko$%EfX}lmLR#N4+8L4?Q|r>I_BtH zUsee;7Ov@L2ME+SlX5haj(Zx^5!X>E#+=_m5;UVpcyV7q zhgGMkAss-Q!2n!|bfpPaI?@oyF@h|2wTjKrjxJE_=rXJPgGnJ(M^v8trsTTAq_w~* z?4S!oBc_Hk1*cP|v65r8LfRxnS)%%^m1sTG^E50P(N#)98=j5I#F9ti(Kdf3A;NQx zHI)6|k~;c9mO`Y*HfezpdD_o9rQd9(LasaU8^9k=lmj_DL`YUQ1)@v@OiWveQIZq_x6G^sN<>Tde=`a?JL?@%Zo18u{ zx;ntB{emtQjq4=&M^{)&Ka9X7cXj!E^(GT+g4J}BXq*H6z10@-bP+zeTLA;m_WtA!B6(*~#0dWl1}uF1B|q7#G}Z~yty zBMb5&PsQD3qjXWC+flkox0fAr%G*kbq zM{S<7pJEiPB0_9<-WV=c_i;_`iCXw&E#24QZm}N~F1o65OuK zRweV4Jx7~(Tn@5lU4`>?OJbJQQJ@Mz?yE>NSHei0Je3q92VKWOU>a!c(09eTCsk0U zr*Yy8+Go^cs$Zms`cy;1FVX>)ccj{GkxX5;3YmX)$};7#Y}M?R;7hBcNn0tGP3HMP z2~M+pd#d|86KR>#iTsgyh8+Wi`}vo^!Ak$z`Vwg9_( z3rMx}E8cqegChr^@d-N|xq@esHL}IrT5|PZxsR1XWE1racm8Nh3E{bpwCO`ljfcTsxIHwv1zE7iERUs2@jl`2 z@~6w`F4tJsI9N`%$o{9^Tejw+jb72r?cQ|D&oS@MCG;cLIF22J#TdUT7XD*^;H#>2fH>VXr88fj0GFi1s>$ zXdgyIJ0rI^!VejM@0l4=Zz7LyrT-W0e{)Wox%^NB|1~J;M_nj_i;fxPCOloQgG#wl z&Y=rni>sw8fL751wA>E6L_Br-LO32drh+$W%UiaZX`<^4yh5ww#x@wQrRB69&eLqW zqu*kI&Rm506ho(3jBm&@y(9}MPL-xh*=RQE zGS%KFKrqdco7+$ZPKApm>|h~#)YUtTmUO=~1FfjqgFHuJ6gWIq&3VeGJI$zKRHcUH zb=2JD&r(yerpbepo$spjq8;$=*hFb>L>b_*2+pWhGT85MEkEpRnYaq~0yKzqLvDoz z5qF(OwHb~X^c!Xnx9qc{n~I%@(IA#=J$&-bxBoa~hcgH9Fggg%n8Wcdhwi2k@aQF5 z=!oJ$Y3f}R{aqD~BD`RpmfHDQ9fexC86HM6;Gtceo`18flB=>a4mH#mxnmI(pM|!=dLC6OL+-BRUzk94;75R%ImzrOZrv5 zXcf_+)>Fh2>T0We%)~O`I%cv>ySG(-sN^_sJAY}e0uDg0+G>o%0vSYkp5q$bSV13G z^VH$s>G}$Je)UyhSxsp$cJQUU13Z{ctZnHiM=hNv{l!3xEmVs6q^-}1y?F1+P=J>_ zJq@)wW-1-a-d3@n>CN}{Z@cj5!T{hb_s_9=3B*|)tyu*G06e@`U?Bgl>`p067)siu z*s_TdoyS(Al6CW$3z#dXwk8sA-iDm&C8A@s^RWO@%~5m?X6mXdYkn2v0j|nme5Tt> zY9aNJCv;?I)}>ZwQge6CmsaiURua4CP=6~OTbsSyDy%nwpNPg$IaeWWRVvYD&(!#j zhKr;=t}VgX%_gg`ZnFfhyLSJh(LJk>$)Kw}Ds+|CZ&$Kq_~5De!x(gReD5a;bX7cL zfC61T-xl7p3fCt*gI)cjc&1f5N3|RMtj;p`I2_y0O6(TY3M>p?dZq;aUB8xnCx=_; zHRV+JZ-U=ig_!*cWYrC|tF9wBVij%J09F~y>AqXNV7tMGv}Y>c3{Z^Op{MiU z=xEh`?zU!q>$2Ij)p8|I3t)Gn>2-yD9JVZcmrdJRspK9mEVgQ2M>EpjO5p_WuL3A%IuElt~R+r4+g;Zx?jgD=JIOz?|qXYRjg*q$*q+Ie(9^EtGm9^J<~ z{`&slZ&iA*RGv?!oHS_X(9`OCN9Dv}k(0~sNDhl*O8`5EyoWNnBW-uY;sN4a zXbt1wD|kpFpf6obyHQR1E~D)7uXLf+83sLcJ7J8_>WzEU7hbXqfgUCr-|Y#kw?kRg zRlNMfS|EbKaOHGuGki4A+-?k$FO?TaVR9ksigMT$OHCOj;mONc%Hqcnm--%ZHX$w* zxB&+FLIa6jfOy&umKGr}6@b807)(ybJBqW6)gRJF0)s+l`^)IbIu1RKOF8nV$o!Xh zI4pu6;3U<RM|b{O$-9td<*x1q-e9~`>Rmu8BmhJTv+NxYs;PTEHW*m3LK)VF%> zjQ8C%wBMTE7P^U!qUrQ|dK7xlayV;W1}~UsN)NRBX)y9DJX^*>|W=F>s(v@MOd z8`m)=9RAMhE&Zyy);u^a-FR8DYS*BlYKGWhSGtIHr8^K@*g+40kIHQ=-zFLsipP`% zu<-G3&=O*=Qcqe|WvA=AHKp-3+QPNJiGoPDRSXNzvXj_ zyq44t&n)lSct7w~+5 zh_iY=P@l1EJ#zZw+d$s8gYU&V_qT#gPm9HX zzgry>S?OeywASj-=18-^<_#9f_&Oxw&hLm4kqPc2&?AP|L_$-s4OM&_s`y+~aX(aX zKb>(_go--kv11Ht>!!hA=ywrAXe=44!x`CW&W(7}Wr_O=H+gV~R#i|RdQd2|(kVS8 zELr7Nb1GTsbe0o^Rby-6=`mL4B9^&KRh|oovh!5>Gd(woMz+}2iOt3oYn_%*{k0ICY+>hYWZe6GGc@eX0A@eF} zlu)s`2zZOJTKb;e1rMoO8iZr2bpTP(>gbBOe@Vu_B>2QCuP&1ousN6yXG9nQ!(gLp zG3=>uHFR`=Kj1IAvci?&njy$D=zN{g_3i-)KLFwKBK6?-xm6wk0?Rxg9dUln-m%?M z-?1gB@7Rc;Jj@R&B?uE;>}JKDTKbYNgu5Hpw>N`qD-pQqDpnTXqXcvqLL7OJ|&o zB=e-%@)BlbT~~1WO)R-~7=vq_3t6JBQ^YFHf(Hn9lBtDtvXFJMn#KS}`_qoCJ9i#t zL!z^Ffcw>uGNe-8N1{KgBv&{}=v@;GMt7AFM%Wz{I!M7=Xg%7GdN=D!>ruR!hSQn4 zg*6)mSmY=czqxVy#P=4EPWEVSug=m%=Z)<&*A{~Zflj))uT1^RhMa$yDIH`-P3K3* zW)AMQK~hU81Y_nV8?${cHG8|0ne`2_S|x#g0<>+6ODc?#dm6tfluFF)}ew=YklF~9$s*d z#SxDCL){X;T{}W`=yjaQSyv)L#LGAy7BCUMs!c$qX1f%n0(zjzj zw?o1!XP;EUcs-33XVRF_1?}eRe~hBWleG0d2|H@WL~udQS32_UD`9I#eP%NjD}7)R z_SK%hZsT4Mgf(&;J^}wT^5m|O)k<-`_MTL1LzPq2Jz6~OQ`>)oi_R!{1Tz7WrI`@=_gi?g0?OEYVuwEk)3T| zqgN3}k!OnSj{nvcLM^ZwpR}gPJW$#dI@39b<7nE4q}vxkGy?1*UOQbT8WRPba7m54 z3oRf9!hfQ^csg5xr%x?yVK=_25?vtsihEa7ZZEa(=NcJwOD*U1@H=L1uC(xHo~c6o&E{tu7Pu(SYe8+^{Y%^zWnFq?6kvqel!y1LFlg!e>`EQE9RJJcn~_j86-u}gtUNecWDbc zk`9hSK(m|O=)xDJ-s2<;eo$s4h*=FK{bZPgx1WWW_*Ghfc7?gQu-Xe9Rj1K35pBFu z_gAS(+16Z!Csr-GvLeM#x12q4&vNJ7@RTif=ARE9OU=q7S;ZR^I@Z1i9~2{D+Fag^ z$CQ=m(er>8he-AmX&1}vt=xgNc=Y;@!a;bB$Kw?GKK|9N@)Kz<0)|sxhUWNOwy$}J zWJ^K7Fbl$)L+XT7#0!rhc^H_E4ghD_e-QX5H+1@57}gT7fejax}Q1V&fUao1`0%l5R5xmste~QAUGZYrzU~g65U}r0Duo05{@VCzxB)QDK?}4y#<>Hl$O*-6VH$4z> zvf>1Msqhkw)qOrkUJzImyoI?zH*<_QgCzWI%>zc+NwP>M}oDu zjNMtYq}OO)AKGSER__?qF00^z;=WJ4i|*d}Y?HJ29FRJfYT`(%wg zm%dzq7W*2V1J~%93Yoa@n-N`LJH6do>LS0Wbd8Sc2AG2J=@K1bb;MxYVOJEOqu+6N z88%?w3Gny;W<0dZ-JBoL*%fq0bs^p9D5Uc%uSl_Rq0JkbW?E_ZFwBE?bCGVB^DK}GC+`~qx zq=VfW-GLcmCC3w4t$X0{QEkOb-i})k=Q=FP?>Mpr2&g_us=b35JO+OxVZ_Up@p7P`V|6N@L<@auuoM&fvMax2Gv6AS^b?tXX*u%aO! z2o0zWhS)*SHXm{mty{qHo4@~Yq6-b6%?Ec0M5kPPXy^@P;(6%*zFZ#;n`KU{to}oQ z>5e}j6Jo723SX$ih-;S5nL&3Aq>uX2V!QFCLpm(chu|xn2FcsG46>_d9hD&D=PMFO z4gt5bn~PvoS3gKSe+Tc&&CKXHoB)mK1$vmyKnU-+4QArkhE{>^7tq3j`x6(1#}y;> zgnAMd>mfk;3k(w299<4ce>#GZ;1$UI61{{M@UKQ310q3yqty`!8cKgYkp35LCac`2 z-+k$iw_J&Kf6w-mwH42>7DkULtfeArU%FX~L`N&K7DQv_+i8P&6?mXC&lezhAz1PI zGiH=?y&&8rknLL#TWF)R#N~7^ySc%QMSA1^i*Z1aBkiz+5Z(Z9=RU}GS*+S?R4cl+ z&>j^uUv3J%LQRgV1HQ~Df_!i1Qk42klzRJLQ0hgFI26)Xi(n;6z0djE&r1DMdW23_ zr9R_1sq?DT@dhTLPuK&cj&u%s!%TPxlkrG9xr?8xA7q*2H2HzxdcZn%%ss>^jZtP~ zG|oud3;0CN0`?!`sOe2Rl%f~Ej21#my2|2`=s3Ivk8`Es7pisx*ylli6YU!3hmPaU zz_q3cc)P`C_cR2ZO+|83Z`dqu!HIq-|A{N`k{(7{@gO_W$?5PknN8=rcIMMcJ!2vb zr@o9v!$X_Hp~Yu`OGu*RISYOZakXvs@vkA~)XBDZ9&eE8c@U&`B0* zYkeE)71|Mbpo_M_1lk@}S+=+JLwBeU;^*?0t@L4qRNW26&^s^TLXQ5J-l>%6W4Rf9 z)Jr;vIi7MB{klq`PPq&HX|d$0FNf0~7D%pvD6~7v@YpYRq7O2p7o_1*5i2#&hYRr; zpKP73(p{{QU93`_R!6i-r8z?-IZLIuSS2{?S$fk|a`G0Hp1emTDDPD%%3JG5%6nCs z@@AE&yhWud?^VglTb`vWZ&3+5UQ!7=rmBP;GgQKk(mKM9X)0kykxJN6q7rt@PzgIq zo+a!kStvmYY@K6LzRE^hR@5L|lpq+ZhtcjIp&Rv^^^)UPD-AX|nt;_cX0-@o7DH~-}Ta3dc%wlpw=Vwj92`CUeeWm zQRe8_e$=yVcQhB1ZM2=Zgm%X-_X&`_SZ{R3IAUIvT;t?-Ob#FHFHh+&*WI5{>2E?^ ze?hFjYaje~N(So~X6&oV7B#hS^oTNa8gW6zh(>VoflS6)4hcPcrLo;X188Y9lKR-c5{$jx!-!p z`Jt7DM*F!Uzz?sU4&hZPR^G*C!>XO&+KdH}tiYRzV4IaT&yXU2iQHoU>aCOKAD9tU z@%?eQbh6jiKTDv$ni>|-y)TvQMyL04bbfH{F+n~w`wgOge?j_2a@Ln?UX@14J4`Sd z@MQz^$L|gXJfU%&)5^1Z+c&{{IjLef__#i;$Z(AX&lgwCudG;A<$Lb@duu+m{P|U4 zi-4E}bcgWq7k_%uP8+8P)b}I=wug8$Z6CYvO~x~wIWpzGA4%ajBhXEJ1%^TgxiRkE zL-f$3x()S_XX$7jJ=~h!nMm8~t=cE9L$&%<-Sx3I?1VjZCjzQ1AJ9$e7f?^tekb)O zJb7Uq#~2gV+KshpCTcOZOR3)ijE)Reuosh)tj^y|zl(UCzKsAB-AP~nO=py6TeW}J zc3?#&P)KTT@?93+fj#fQo_+ASNw5h*#PiP00)0nZ&Q3&Fx=Sf-0`(n>Ym@V=&I2Ym zASUAqpzZPAQy-suhMV9;5x$VEXW*_GANlpduiWmYQ)m(u=+Gz|j7}FoJOrLML9#&O z2Z>Z`N3;H0xJxpRc41?8PgE~=U_Ge={L|{(%pRU5;8^$wC{4 zT=@%KSMb}L@Ysyc;pkD9WdXfurh^bPX#=Nh#_Gh!>}^Ladbt$7mY1U+`nTWl8>|gl z{DyG7SIZW(0rmQ|Ie6KPh_<}u=x2fsumvfs2fv4S0+|8ZZ@maD=vFFig%h+>#b$b( zZUpT>+5+};r9q!;NGGd<;gklGy_9*m42nC<7poLwI(*1bpJ{Ca}9SyJSc?CSoa&sLLwcMa>Y&h+K zUyDH2Wu)3&!MY_h@Nu6{e#Xr#1ffaqClwhv-gW&3bUQ1TP*+IaXMpsa%ANwu9uU-e4oObrr>l!@U@)7&N2ERQ2AM23 zrsfJ-<-#v)8}K%1muQ+i6TNHrWtT&kZi;7*`{>~{V+megB-XTvh)=+@v=W>8R6tK` zYNT7``_4#2pT$e^T7hm5>0Q@amb|Pcjn!e$PpwdwGu&8>{|z?A%1gcRbe1i`z}N8w znSDL<(bJJ)NR%Fn3cK9d^i4v$w}=5SCd(EQhUD`N1O?M!N-yjFl3vJrq<*NUG8O|>p0&G zr7rY64Rh{!Ywq3|uTS=+LuxjUUNUCoxL16QY52|whcAL|<*L<{Yv%f9ox4_c({ktf z&LfxXs5OSafX8zIKW|y(@}(<$-~D*=%^T)BFI^k)nGJpV27fHYKcp~s?wpF*%X|-} z#BAwe>D;ksL<;U`_$40v|0ke}U0gk@a^Bo&zL_sfOz3P5+nRVJ(MB6mFG0=)!9;D% z&}oQYaCnRwWdqwEc(iClO@V0HZFmQZly6eJX^w*zMA*0+kD>TC0L(Bl5Zcp~7i@Iq zCjyN-I`9Y@3w*?M10td07v215)!V-4NzJD(>gdaPG?_+L(J56l7oS}kVLZOL?&||> zb1(O!dNX=f8g;-Mbu6ua6w#YsVBZXg)RoOyIB~7*RNvISZ7hh}hU3=s8hsnLspc>^#t)32pU6)? zX{S`zHLhzjn@jKVHaV6j2(xVHB6pVFATsKr!T>|=Z% z+Ihq4uoQjF{`4Fa$Y)`=>#Q8_7>Vz3GlZJ5ns-Fnb8!Xrhn|&!@y>p*NpYj7mxZ1a zuU~oVHwpic!?;TVbWNn`Khd5Rx(c+?;NB2;G3{=*9jq6=KTL|5Cz^nJNEK8APo#_xAD zh8%oqp@b+|`Ksy7bYZlJE4Z-F^6_uRZ58CB1%|Lnh z`@KrF%X=rAY3JCamNt}!GfO__&CV;s97&K~2}7!TKt=_O#J|Y_PE^6m;t7VNZp3Jr z_$_>Z6BkK8a78VSfDdUh#y@mLR77EXUd6ZcLjj)y*r7^1&i*3FNsRs=I$OX66NW=+ z9G#CZRJTK%=@qqtAiCya3LdaR_JG`3-xXu(h~8`HAXfiK51Kl`0RjKAhVdsD1q)2@ zK3F9=$5DYe9DU+)(LZGuy;LC&udZMR27h>;cBJnk1XSekbKAZ_ucOODwS6PR$f@zl zpFN3j|Jjqj;{D3e5}MEw4t;6~muBOG7`G+tfR=DJvxG&sZJ;Ie5VwNYUbKY!6-($* zu~D&vtzq(R)e@Fa-!5)TnB?rZqp9B>)OC-FQq>ZUUgo>$H%z)M;l%cS-Be4cdBzfU ze$EoU_?#uoaa%&<2biVFcUzjS&sdrjXlZ6CmS)g1mZrm(Xla%xmS)^jOH)awEI~_S zLkm$*YiTaIEltA?v^`oH7ggVb55aL1<~}UpZN8X=0hB(J@Q23@yzvHjBSJZ)#5C!xCm{jJie4)cjxNeFuCL z#oPbP-tAquC6@#^LUPGn3MD`Y9YXKDh9-pGq!;M|(xoH;1OZVI5fl|skV6zjMCo1W zAktKda0;T#C3DICzcY821Vn!P%KLf$@B8k4p4r*i+1c5dXPzlfnOc(6B=FM5c@2=7 zjG>Esqy~#Bl?1Kn4O%lbUGzkLTC;NZpO!&Gs{3dSVg<295CnjMm&KCk90t)j45G6i zL}$MsI#4XjBRbI291W`Nur%z$3)%TW5S-0-E#UTx2IeC;&Fp+R2u}L=c|L+uDI=(n z_ziY9KgGG@< zoByF-E$*Ft%YW)%LvovcALK43`t?Bbuh%re;maKi?AV~eftEGE*Rt-TWj#R4I-c(7 z5olT8pk;l7fm{Z=vBb4 z2xur~oGqBna##zVV@mT7mACK`lb3)HwD3@~bqLckL)Tj%;J1)%6~aY0LHccwbwA7w zvLoy$nr9Jy1m|Hq0byl_`C)#LA5^VFJgu_&*dV?0Dqm;fr@Xh;Ti7Y@jX;P@``h)F z>|kS7j2v;sV01Zz4abr-##&*_rFy<%Elu80X&8X5Wtn2Y$=^3)dc2N@rDHj3op+(k zXKgc9x7MoQ47W6~aiH9tF`SrV%hK4LbT%-jAiFD;^)k^Xc=!u=nl%$o*-*3h0eiv2 z*sOFmJV)bqRX$Msa4}C^TNd^*Y$9&>z;Hd?{X3f$fA-s5b{im1(cwQOI87fr^9p`x7^N^V@Kit~i` zBioVPM~~cN_6yw1s)+apWcE8?sYa| zc%^sCcBS(^QA2#fhXl6Fu4sy1upXY#W|>zEshfxv+Q`KBWlH|6u`sp$>05*E+OgW$4RijvKaalD10%vhK-U?>!XBzU3!u&D*Tm z)Ya)p_0&+`?eTi2lt?Uh#^G#?Zs9&g4$s(FyZbD0(?`zN-+XD_t5bqX{CKV^OR%F7 z%CjPDjB}A0R+*w%VGQjmR4!AmnPbv~IcXE#3c6FN$ypAv*b|DJn&h0ade%E{zaMmT z&++p=+ZURCJ5;4?)(Dn^Z?0ga?g5~&bCqH$}+rn#(p%vPt-$IT;sR-9c1&FpBp&%b`Z*49~F&KXPdHHN2%)}A{@ob*qAqSIlG&^9Mrcd z8(Wkui85Y*GA1Ux;7wj&9ax_zEb8}R82{A&rfAl45Qi^s@+5dZ@ESeos^PU_ zF?nLW-$2{%Fp`P)d?}{Li%p)_qRgN00qNehQJK~G7nx`HZ@kbh%v+Q8sn%7VV-s!c zJ{CGRdwO^>`16p%y#e!PaA{2%vIT7B+(_4$R<=k*8MYaEpQ z%kj!~>k8=Rfls*5Q^K_O*(0;QU3z8Nu`Smx2SGAro_TTBXDVNk-OQBOx_a9(_PAQ# z{p8GS%om!i;C2}-+?X7l&2Cy2u)-E=lzI?B)sv%h3g5J3?kUQ8qn_%bfz0M*A(Y$` zopCwXjGN70WMz3>*4LT653eC2H??!)zuO$RhnbGLuN0=aEjyIvW*}8jPsgIHzKPw> z9L8^D_UHA}`S00-R8JG{RvVw;`2s5R8`uo*#}IBClX;m#%&t4Db@U1&&YBO@=B1K5 zVNC9g=aboN#@HP!MScon0dInpYV#_5TuB}r(`n=f_ug=x^0eTk(_eUI!Sp$4bC*OM z?A7XXfu%2CJTj1jcQY^z-9r?s41uyAzdpIwx$@OT881%>>h#uEeW7Uqq^|;w*G`Ps z@3VINSMNl09$66VDgkx6i=OA4wLOb$Wx8Gi(Jy~XEPvfOSDBZZ;^g7e%7V^oK=hLy z*GwDaTB?1DK|)z43&$ebhv}%#BiDtC>1ujCZup?qkDihLbF0CXgxg7dHz&&c5>+i#4dr)jmmf z>+_y@ye4Eb(El=sOE>iSLRg%4rit(7RZ!c{^988)D(uB+sL4j2rJ{Acj$tE)Kuk$F z%Y%{waM_h66Du>icANAR`EAqs#?acV#Y^%om94zSqX4q|b!ae?s zAgE=~C)ZBeT$@GLb#f)OenlP<$>T0pVm<3QSk<;Fi|X=mYWv6<$$c?Zjw}D& zR0rJKBdm6DHq^c|Gt$N>@H%qWh>s3Oo;Z5!*Owjcfhr5`@lopH=1XceYg+l`AnP^D zORTMpb@_wE+~4Npg*L0zdbev=*3LtdZ)5qV`9(J?@Wb|Y4K_MigY{U5PsL!3VGbd>JHW`eE*}g0EoxK;2e4|1e^K z80=gypGJZw6%UP=fh-oaIg*b8(=~<F7IXzPp*pvn@MhKKEhmku4h0NR(IPX-*(W*4)~8~U}1X*H%Eh!(E)dM)*jMlakiM2ryneE z{<+}W(|_0>9BmLA)1pC~)0!QHWg$?>7E$JH81u;c%*(jX{1UerQJ$6ozcs;gdWsDc zUd3{d_KmX&R%AoU)#{C!vGqL5`Z=M<+L=v5QGXW6T2;cr;aK!GwXueA!QmZZ24-3g z@|a(bt9;5wEQlM~XjEw?*6mJX#qRL=yH`I+Da(5xdQ%RWI|pP1JO+`oIi?<2w>)%E zIvdG7!?t*q@OkN5yh|X)m(E9e=q9Y4b@fmYbDpWc=LMEIG@Xs&`k-`AN2U+KfQoyD zf9!b|f)`u7?{d!u4B(jlVY;^?*Egku(U`eWwMH3ViZZVdocL503Ql}6^wNS8A0j#N zQJE3ho1ohsWx9bOQpv88DZlf=-TX}X%srll(`-PTIMDt|Olx_I*V*LcwOwkJH~RwH zzumKsS$?}XfRp8DSSAL2mx4%slpTF&$>O{!kN*h*10x{6*;lZA!K4@mulpyIhKz8Lr9V5+6EOe)rV%N)>k_r-n#B^9z+@E zBv^V_dciQo9m_95{@1!eN*7r(%S9O%V&D&rG1`QY6k#-oTj~payNw4j`rzdwK5;86 zbONCIgas~0wfJ-a8u@hria-~@npN4z){VIO+d}r55PqG;pXvD`FS0Pmy4)L@WLe~` zIMKpp9RM%Q!sgtwcxUJTy`1vm2eVuHe=)nI?{wH5yk4+CdO?l#1g5}!wO~OuuV652Wg1u6z9@{nW?}Krf~~J2 zu;or!Sm&$(`Was>>Gz71=LAHxdh9@x-42ZNNi$)6+#mUlzs zHalgpty^u_-|a-Z%Pn?xW7C`-%FD{z%0_I7^Nn&qIi{RaE+{`@L!3VqZZH^ZhG;`s zY+P2~(8|!+(AzK&+u)2hRyK||zGXb2Qnfs+BhFA?Q8%gku<6VlHQQu06*Cn#RWa2w zwKhFt>TMci8fhA9nreE{w8*r~^oD6YHkkR$906O2r-BlKrUZQfONd&58U+RvSb%L? z4ixyYzyoa25(T3L^(`rueo&2m!IA-~uXik4z(GD@IR~*CH@0F?wGb^*E1^};YH0Pf zmRgF|1>3On(}rndv`N}b?OMT71qT;gQtay;#9<^SuUbp^k%?UAw6bgwBNeKBov}Nd? zu+Xs7u+?Ed7m6!1sL+N&HwwoT?o@bg;m->HQp8@Qb&)AWHWWE)Q*7mI&)BBh-mx9A z-7gwZv~JPfMQ0XWQ}mmnKZVoqxbTMIeZwb*FAv`mekA->F%@lEu+Y;3U%SULQ% z*qLH?B9w^mh{TBc5uMouUw?%VlZqkH$eqEFHCdas=FEko8=+epuVlZdk$;zK` zY70OtZtxUL$#(GlycHk8&%;=6uKAxTrk3M0&tSfYZSXo=7ERhYv)VkdES5r&K zU^ieSJEr+{w=jL23DZb3P1Z#g>tc%)hMTOpa-P<#GR$Vt*7IJ)SUU})ginQiD=k-1 z9SH}tu{A!|ryuV7n`S0_Dk6v#rG?5Yg8X_- z;>D&GjlXqB<*^%E?70`o==EP%3WnIWHoX2S2TL=tY4ahO-<99TvKScI$@~?}m*TOw zFgn%AHZ@n7WANE7u@E%oB^rX)(1J%^U?qn+pbez)wix-T>pE>b6#4VTPr*|$oa|ER zH3#%YS@*fTA~Wz8?UH+H=dClG8ITk*C9}o@Sl3>~ZcTJO+cL5e#+9M*#Xo1}(GEUT zlt$mbh;i(ENQ@&spBTrb&#v45$Q9$LohQbDbp91lO>4DZt2`vCA@ny=v$cCPp~@_4b*%-Ok+a$&fgn>w0cS!9A_@{D$vgxMwHdEDla|z8++$G? zFSe}1(oK=?Y+T34V#k6tThrFq*)B+aB(WAB&Db${i<33`AcOU6G=f)Y*=0h+S9Ov% za)%uzC^|wcuMZD80hB4)+Q}ovv~1NRvf||-A5Lypx{XKG z`VRB5;H#&xAY1rqL%gk3ZO#ijKg}L(0|L@7-RFNea&@kgy*dR`*x7qi8%HM9NQEk@ z6+D{D>?adj2s=?r)A@UuK`M(rfH{!DrbfcLOA@QWFFU-K!OY1{vUx_cQ)X82kLsA^ zByw7jw+4^zsV(ck)KOm(>yJgO!P!mNv+3+2$imokJ|H`FdO9DLnaZ1_^MTpjU)xn-tGs`O2HaoJGv(IvtgJ%OHU+Q|WVfg1c@9`a3@9~yC@AjR5?0^RY2d`bJ#1KAZJ z|E2chPy?xAQ4}_U>SI1(#t+~AWdHRZE^Am%PS@Dczbf&9cQ0+@-kTATFIQHSS|bOo_@B{ zE%q|QgX1S|-#b~07fo|EPfKnBnuNJ{VJxYA0p+9mF?`4j(G@(|gun$>M%fgEIwAfgn1T4Lj@Q95Cq#R+uG?kO}F+wmqfmMb9rx0`+H6gV%9kcEl z-cU&K#-aP2>C^(+Y{(?60<>;{=Gu-8fT$4`2wNP5pm+z~w-#iMYKd(O{;>?7briNk zFxz>pz;+0|Pn&Xe=?-DlbPE4Y%lcbWCDy-JGr-S^Z54##*Oh}kTdj4zW6`Q(khA^B zcqa@s@(LSSR86b{`i3?2#2yd}U_D@xMf0qlXk*V^V-df8;9SoKgCn8|3oOD;2lW4> zoes_4If_)GYobHc0y3=$={fxc2TL0RLswb(jQnXHb-!hfXUlWwq6cD4qaYiO={)r6 zHK;rXbPF}uk=!VAz;7J}KLF_>-#8Lo?rvLVJg7%J zh*1?-q8(NX+jB@R4!AyP*j_^{!oDPbRm;^B6P-uV%=X!kW6-MYi^0Ah1AF#F1wt39 zI1|KBgEEwl^0kBAj1m^jo^SkH;w~j&J!8}ycunosS~RZ{?eGKdAkEW!Dm10F z)M2eI2!e=`#^*K2j$g&^bb@80y?iXX&UYb2IHFMr=SEM-%;xFKSnr(h^cLBZS-X0# z&B;iAbxFjX-_NbSXNP*D4Xc6GvHlzi$(i;T5}MEhmu}$X-Quys#bq`T>eTPst@yw- zaQ;_#CV3`8N!);j}y`-_~y{vy^V zThy>}TeZf}gel(m0#h9@lr%rPn;FUvT{yJv(;Ql^5b|SXrZs+^_2E6)R}TJaX2D0T zK4@9J*dWv2*;qy0YqzA8;&L~zRvwgVrPv~@6l*@~ki&AeLx4sMM)KK?G-+aE8lihD zY~)-*1DXQ5Ifd=xjZAI%ezAW|eO6nOD+qbZ8^Q*)Ew^1l*4)=Fz13~PBH2Bu{!W=N2?xH68`sg|<$1{W&z}K0xu7 zm8xOeoNB29d-ibp#~uD*hL*ccOoy@9CMHk&RBX{wkr#D>9kOt(cV#5FFUR--?{6@a zqVY+Q5R)p2rOoaR4U5iOAV>TRYsj~0q9A-b^bGXViHgGN5=cXosdpX)Na97zwMQ+# z;Y`yi=F6E-p_~m}N{xT8k*(peYzwA*if^&3@ER?Uupj|gNlLoL;vo`N>M~1AW*zML zsMlCi?5L{I`6zaAZt9X)&vCOIw|>JL*!fcQYgV2*Q)~wF&hNi${}tAJLNd;_;i|Ca zlQd7|*_f*Fpi>sl`OJdQf*$Q1l-na0`jWL<QH|BkU~r$3EruI{E4xFyE||wq9%R^jyxgt>x;= z+%$`85q#TJ5T6J>NaP3jq*lMeEIlzif(b@B!)Jv@Gm?50xo29{8-f9&o=@iLHg1PP zxMf|bZ8e=3HASlIh^MuU4Y(-!&+qpReP)ZpTiF|{&e}TfQ!IKf<_~O@+il+8-|4CD zDWR_Dy*RaNB=1{W^sf%9XGkWDs(8wQ&Rz0U@+9(W?3%Znw>;RW*Sv||N{}kPHzv zyRmfZFE3p=`t>ir9O+ywxlOmyPH%l9w=~>)?WZ#bP-ywo3D{&ibNCg3#)H<6!-}|H z5ol;WMW6>xsR&dXia<^bhWv^^1yRRB5lC2x{I};@n#V0wfJXaOfFS2$`8rnxXtJG0 zm(H&OG+wFzt%nLw9cHQ!{dr9=YYN5js`Ddiu&X9^o>{s<*y-I;>3F`68M}fL@^X^u zslzvT*P8jbnme$x-{?>}#J+ns_!9ndyRk6d*v3umB~Ns}Ir7ytOCZ;t-u=$=9RIb z(sC19I|_t+DF4>(Eso*h+unYf_Z`vwgvjnEI~Zuwnw2)QbZ>o|r#{;c7V~~jV-{rw z);`=FS;f*!sz*^hW4ub%DAqqa)syVG%ldfldXlicfs}5#YT^rFjoxF+?4V|MFoWkY zTo|Ii0a_T8coQlg1rp1nl~`|<6Nc#j5QgY?@7u9W7@}|Au~)YaPU}ENmGM<`5p9@2 zv@$+KyYdTAS`CijkJ9Zsg!D5#mU$A$^%^(;| zjpO@FWA40g?MNgGx$+$|XfP2VY^6N){1t?H$=x6!v}odQq>aa<*98%n7``n{oj!Z% z$_38ZU(eYN^-Y=j{aqdEY7iK^avo;Kg$boeJ`;dipzvW!## zN6HzK%oCm2b&NcPYd68>iDTMtSRL!Yv{F(?L`&i*BMi-chZ016K9dzRU0b*1f`b(| zrGW%u+cVxUDT&u`0%iK32ke8ry~L=KE%7upp^IGSshHiFy#N^4*k8?Jb&U9p}&{2iTBRj=u_XT>{s9O zz_ibl>1Tdl$kGIBWhSpVXi&v@L6}3>EV&Du=zP{6hotm!XVz{$KL@%$H3ooXE{sO^ zcgzw-qd$Hij7EF9XGTC|4-KgSR77S$Mxile6huR645s-EmdG2(hBT66YqxFArA=TS z4g#O8P3vGPKnk4>GOc)N{!AXZAZ~DAlQ{G$ zldtEub2My7)qtI&*=r^->af0_wqaxBhK%lOoOB)}}MhNB2ihQmeLI!QI zvT_7y5GJ4PIBQJQv5<{w)6ubDL+_dZ)%R zi!$iFtmiecImgT@E%*{UWaihHt)c)%A_u3NIWgjQV%oZ3blS*~kwZ}+K7(UK7#uUf z;F#xEKF6#<)@?q-PUl0W*~!0VHE@L;sdZ_Z7h~ZFPcr;MDFoK7Rj!+@Qn+&n)Or*) zaKDd$7U+k@6>j29p>NV0BIgk>jUbdpU>xOez*Y)&B9wcXXn7jV8==wMKx#BUq;diq zRW0x~c1^?HV`3jOY{MtERkPz>Kr}Y7qu5KWC*0oHbxdqHwiNC%v9}-g^utDd*pcsN zxHm`+p_I^YxDhl8u7k$IEkUt$A1zCp!EHsm!cC>);ZCGe;J!f9;bzcY>-=_S6dL}NcZY)_}Oh1*%_0=FABoHHm>l)2bJEeQDxC5TNFnF7VmZ&VqDdvV1s zYVZ*-2ve~yoYJ^y>rTWvyzjV?U>GJNyb1|wklG}MRB6^F4{oa)dg#Z)f_o~pkGd_j{<9UeI= zJaYf=^RA{|I0pbmn#RGMEbo0`B4n~@hH0+pkm-SG72LIeL#FqndkSF>o#rCG)8xg~ zD$gQj>}6(-LGI?DL}N%4POCI9)>Dz&3<$(lulPa~_9W=eBx5J;8g`kzFl*Yy4LN5FN!Z9ulZA6o-n0ureJ>>Ek#00$al zbNx1+T-4`2=E)bth)@-ARm4>lP5&M{1YXh^xvXwp`8n}Az@ zUjVlOcK~j{uYlhGcLDbRzXR?A{s8<5cmQAk4gWLARCaQbE@i$ngC`%5TF3S z0?+^j0l@$(AOsK!2m=%X6b2Ll*Z@TV;Q%`z3J?u&0GxmrKrA2*5DzF0C;=!5CfU1CMfa-u`Kn*}mKrKLRKpj9`Ks`WxKm$NS zKqEk7KodYyKr=vde6t0hCH$>$Z4GDxXbWfuXb(sMbOTJ#Z_|l@Nr2}8lL1ozF94zYTboeccIo@sC5@=-Gy3r zq1Iifbr)*gg<5x^)?KJ|7i!&wT6dw=U8r>zYTboeccIo@sC5@=-Gy3rq1Iifbr)*g zg<5x^)?KJ|7fRWMQg)$~T_|N2O4)@{cA=DAC}kH)*@aSep_E-HWfw}>g;I8*lwBxg z7fRWMQg)$~T_|N2O4)@{cA=DAC}kH)*@aSep_E-HWfw}pDPNf1rd zKcd|MJpercy#T!d8Gwa4`d!5P6a9+F0j1~31oVH0NO|cK_XA|;Sm~mFraOTdD%}oz z`2w&5@D<=|P!$R~)?2!Ee0R5ghwcUJ0~`Px1RMq&0i4s9h_3+O&goYXcf0-r{hU-p ziaAK}2l}Pn5UKtE8aWIp{~*&W2ikOtMA1J04*(w2kjQ&c=`!hF#&)rr^z&ph;A6lR zfD5n{a9MW)m)*c+H*nbvTy_JO-N0oxaM=x9b_18)z-2dZ*$rHF1DD;vWjAoy4P15u zm)*c+H*nbvTy_JO-N0oxaM=x9b_18)z-2dZ*$rHF1DD;vWjAoy4P15um)*c+H*nbv zTy_JO-N0oxaM=x9b_18)z-2dZ*$rHF1DD;vWjAoy4P15um)*c+H*nbvTy_JO-N0ox zaM=x9b_18)z-2dZ*$rHFgAy=M0tQOJKnWNq0Rtsqpacw*fPoS)Pyz-@z(5HYC;;5yjVImVSd^p@GfwZAm8)gJ`nHfZ|k7; z52vDkrytap`@>=aPf?=&L%)^llcnN|p<`ocq$l0LbKg~z*<+8Aj}7$)qMZ>PTUQgi zep}zFPsQCzy%*eTIGG-!r(m;VP5+S;5aV`z58yRD;h_{mF@`519p9m^!?hd$eX)*y z9&WZML(mbTA18QM|6OdL3@DA1e-QO4?se>${LoPe<0@?AtxrUJ{~`ZTejT~Jt^cWC z5qSr##G&8QKZAQ0BQ~Oci%}ZUci`Ixa^JnC{}k|xIC$>XyXQTZAyF z8NpW@w=t^BJ@gX+FX|YhO4Q_!0qPKV;=jg-E1rJ{H@Ee`zuy-w-5-UEBLd;S3Qt~{ z08i(LwkFH`Q}GNN#seSaQ6e{9g#Nle%X>Yrd6@z4P7 zi1hL75JG)Nve-a8_e(NNm-UZWT+f2*28R1`4ouT8>APhlY)!78(|-fL|D>PtQ-VN# zeJKk!22c=x_MJ!}P{;aN@d#~>>DNI&HKZX!5OzvF0j<>0LnEB~{sQ+Oh$nwJH2oxE z3#Jxd3R6m^U*Ka zHc+SH(052z=1M>6&tGALX~gC$EreYbad0I2E^u>OsPBD*$hy(@!q)(A1ZsGYd;`z) zmju`JeXx#g z=7FF1e{m1LOS+@vO?lie0Co12k_`H*qxV6qK&#C6SRV_vNcm!qsOdiq*G*N~E zFMMMMz4jyN)WLm>=$T|3(fj%E;ZGS46i4ECHtxb?y8#A@19%kadq>`Fmw_0=_^zaa z|0?=!|B=^TeKbn;?>F%f;{*~eBKc{T@Zu|e+T2{IaxAo8v>?%T^-cNOc;F@fRrX3OuO%b4 z9MuYH1pifl=4BzUc7Fy3$7n?hzvX%a1|6P<_6*>KCPZN1r0b?sEKYBA{#f4e7U{ zU2=T_dY{|C;QX{tyyib-Yd)dBg6FxI7^H7+)`TO#IC~npKcaMB)w|pkY z)qyc3=9}W^Cfx%5K0hjd-N`2y75lEa?@bgvg5Fb)li|_+SOH3eTlDg=fzW^Ms=q1X z>qq@GL{N&#VqH_;F57N7IZ8)=|D;s)6@Pi^Yke7F93#hZ-y%kC`_`Wi#Fy0Ut-#&i zU2`eS-$fANJ>)~={J-Gv;fbVIBK5$i=W$z^Od}C}W`lKrWLD7Bv zC}=s37~#k{Nc2? z&pR*%0?p7D<@`#FdVPe)07M_P6W81$-&`s;>}fsvuE)ppVJ>RLiIL%1iHjLBFIVNa zV;-i>VmAJm1JpC`5Pg{M(7zK`Nki}YLoUmZt8&bH8-DzwoMj3cyV)1#ude=kU{>{T zZvGncX+oZoc0El}xpDr5G(iC{PI(_L7qdBBMHx)RXi4;>MKGgE%T4}KkDwl+ zbHJaNe;z^Kz6RetA!pY|)pK{AEIJ(SGCxlr$I6zBC>D zx_RK%y-m~Tew?f6HTo0ycGq#P75q554*WQszO7J2r5`8-6bs#~geW0&ivn##>H?2B zif&aLii2)b;+1&%sgj^1(9e`cN+Y@*+`491;Z{gLd^-Ybp^?a;iat6DGs8}8j_CSPItn*(Tq9SGw92^f`1-CdO)Mk;{nEwbKrwRP_bgWfmfa`9BI_t{_5nRu3sI{&|`s>Jh z;CH?cZoFCYL2cv{oYf^a)IxTWZ;;>J zC=y0TOAf!_tp?GlbSg=b9M&NEBKRYbsJRTp6x`Ne)ZY>kN|(~5q!fLbzD(liGP(>Q z%jt5GKv&Qeq%?hnzJidIbR~(WuhQ4yUqx3T{u|)b#-ZL7KEuTz~=1olu; zLUMD9D+a{?zu@T>S5!qMl?7Ijk^-xUCa{Xc3ao;J0mKYH?(}%;E>o5nGYMB5*uRjVS_y%HaH|UL`pnxN<4^>7+{wekSH-A z0o?oDz_~qi53$g_bRYZzC(6(R^dS6)!P^f8SN|%WUZXz(;{}!!p|`-r3YWN2g#H0; zRychCepWbz4O_T^=N}=lCstxl5s5vq5_?KXyor(+6Q!6G6Dch*CR$<%m6$;#W|#%N zfecK0C56O6)}=FQ)(DD6QF|2g_9)cTW_kiOq(~VUB4uD~xEJy-f_4f?9lMm&sVOCO zx=Tr&X;M-rLrUtri@N`rY?P8Z7p0`mA3{=x78GrrhEhoC(4s<82el1J9hxj8b!bx| zsYCk-NgX;!$mq}sLPm#95;8jUc_E`iCkq)JI#tN%fX5k&++YO>*hoON2w8~*jXlWa zYWxmH#sZ*{PoR`fkS~H<5wZh-wHG4B(8ussr+|?c09OFlQ4*My647IL02nKSW)W(6 z1pH~!q6ioAM_r5-e08R9=`86VCS9VgM@WBTK|H;05K>E%WSl|5RZ@(CKUqbFbeHk3 zNtYNPyMdO6#6hp&LfA>T<3WEZttI1(mhJ-S_7g7cBfdfhNPjQsBAiYSlXG~h$C~qh z%@-oDS{`}6Fo6vu4EXTR`$7aZkr32*2=D>!dcc#z zk2e+p>#mFR!a!sG9bd?6NNr8X`jCzPM|{gfsfi;b&zDyQTYS&(^fMU;YYzXGZ;wpn z5K{SfeBa7c&LEY4-ggmiT?@Gx@@vTd7N1<3mL>AEzAO=2kk^p^h%eM6(<_KHpVn7M zzTpTh9{PXHS1k9>bA2KNWmg82tBCaN`d55Np#q?qOyLQ>(AqLa!_emc!+mY#e{>2> z4ecX*;&^J`7#VvK-gs8}hQpT^mg^JGP#4K~y4L3peebD#)BJDD$$P^W^0(=w`QLac zbcNryD(~IUkNjaQVPBMulNKO zhed|Pgq8gN#~1n_ke7en_mBP~)QkUB!h*uAdA`8c@NQzDPQoe)pQ!zR%U4&X(io}y z8$P_<63||z^-uc3y5P+oVg14e|1b276eS{#u&4En^To#-{~6z8`Slq{?`eH=b90a( z-(8A#S4!V%_}-Sj4e)K2zHRXB5I%8)iTOGS!;IZGhYdRg-vt?V1-|RjcL%=TrOyMG zD&GoMt&i0xs>X_WxN<|fUr2YajI&t!!Nb5bf1FtRRj$jBt0KfuLEQ*f^hDG^q+f70 zC@mx6(5liu2WzENDJb7MDcw&*xUx$62g^9g(!Wu?NPBmaZrbs%(&c$eO_aob*43l?$p|6n^6=nZkJyVi=9}a%$Km@Egmi$Ka2VF`LRbEo7V$SSO}Rc^M*jE0lIH zTt-Mw5kgDJ^k>U(x$2>Gm;Ptu(@k>aqK@=0lm7bB|BCce>F+B2zSWR)>5muTiY$Mk ztB~TRlSJOA8S5gHwvZv;$dD8fqNK|B9mIE){jxSYi4emFhG2yBlHr+H&qkUue7+2? zDZ@{TaKq;!oPHu*MTQp>e(2PQ|2H^v=UDZw`Ivk$oQpY3cvYW zna(;RR@Z2f`W@VO8IoeWiF8u1B1)A@vh;qI=~NPaLzM6veWiLu#=Ih9ek)_15l`uC z!+hb2e>YGWep`mGm*E0i5DQ?T4khssy|k?e59pZQ$=vJbdK% z5oFu&QT>OL9n$?qx(5(Eh8!Cuo}L;tX23{tVYKjH8!OVhId;g%XUVT)$5yCF{un#H z-&m40cKqnEl#D|hYC`!)ER*FVc+gmLMVS(mt+)ywMX8E=U&)Gli5Y0G!XG4Evvfsj zRPxGvtF#L6FIL9d`lKZjvO;Fq89I9rhYmmD5g3w7^Mw-z@bTL^1 zO|?Z>gAc{J?qd23?S<9%rC4=e2HwjGtg^4f>iTPs4cksXr(e(=(2Ltizk*)e*Yq2D zkN!^2iB)r&BUXeJrxK&YDskX|6jw?pC6!WG>&Du#5{5r13p&1Y6o}t^Mb1c~T%S*p8m8ruhj8$9@NJT;M1eO`6W{Tb4mE569TAdi)ktH~ zf%G9G$yAbt6>JmIe}`_O+wp~?xLZZn)6FP{J@gpv-k|T&k5MLj>2chxrti@$D4%`w zTim@#-={8=)qeUN?$*!^bSuj30M_zN;8cA;KS3EDq$hE=mTsimP@aeADcr52AJR`z zwuk9y+`UadqMxChkI*w{-2x{qz&T&O+oO0Y$?`M!L+avr5fUTAjBt(05M`(`9J;eU z{y|S9&|4V{Tn^v`MXI8h1rM-TKF&j1`K3gJSb*(CNt7}h9EctYbTO6g%8PIZLKjz2 z`sa%=UB;LpW6YE>X2}>x9bfJH&^LX(MuFTg1#QJBaT6GcP$O{R71VRj+`o3ne^f|a z)Dnd&{-A(AtflB*U<6o%p+5i}zKs<8bt^e37#ASa0oO?5@VAeB4t}lpau4}Dw}ilp z6z};{gSMC8)&=e+%iILMWCBNCeCM}(F}k9T0yP(h{8CV23O=8Bhlmjd;-AY6FXIm{ zg7T-px^MjVK7No1lIxQ$pcqe} z3kI|~%w1(0wt%iAfKulB7V21(!V>x#zGaj-6S)HqTT(g`_|zE^qoG|c>s;`>1MiC# zq=5cG{~TALY3rlaL9(pGp9=gES3+Xoit$F^UC~-Zxl-_q17QkiMls}fJ!rvuX!9G; zwl|^;eR6$9htdc_6K%t^UkD=Bfo7B~$@qaa#el9Hq2 z`a{0(E%2{K*d@R<_>*wGWe6vY1*ntp9e{E6V_+G94m!SP_>YTQA}JPy>Ck>)=DQ##7yQF!qQ z@AW5T%(MRr>I{@WWQm>#(PX^(2pId29{(Z~d)oKR@uY_U<2I6JY(zRf7PcXL0$?NH z7l62*gm(fkJfA-hmUoTHjh7de_ikQTFGB>WZTyMU_zNsW-aaP@#-;lEM))C@k_OuY ze$YRIO@R++cFtMl6G&$u-1l7n9{vf+6#bquQ}@8HD9`DCD5drDN=XSvj1!TrfR%V> z^230+Rhn{|G&TK*=Py47*7?Ikx%^`&^p`l7@ZRI#(X=*`B%=U?o4etit@!Q-fUTsX zp#(|uLoZzC8cOJa`yob+bpBh|gZC0hD+$B=SO2~7RWju<;CM7l?MkLR4jzq{d#{k< zrdX2jC>Upv3dT01_>;hJf;4#)j9W+#r49KIZKgKbacx5d(!)@ibX2R8ipJaUHzD1O zCrLN85b2?saV?3f33z%G{?gLl=V{}qlgL`Y*MKhoD*-bBZv&PC<^tvb-ZX?l&J3e) zC6go?>X3Sd;<#2LRSmJEs&WDTHVBI)$^TvP)DC1KJ)N_|beklC-X{h%BZ;O|_`8vM zW(V#aq+U=sscIgInZ$iESSdid%d3S9Hl^Xd7#XibknzS?5^GE#4KS)44Er;K3`0qE z;~r8^xlAG?bS3MQuIP)VlNri<;#7_j8&a1vuC0azI@rjQ|`4>$HD zT``6jZVV^wj5l?U;gtTi@r3@f@h))eIB}TjkPzc{Bu3l^4I>douIHfc7~mN|8sHZ| zf52+MIKV8xRKOI!zmD=Y*$Eoh!#J5tl+ee24ctGAdjWxaaeWi8hKvwGff75e^0s_)6n+a zq@L+H(%RUBv=&!$8&cG;fut)%Firp%Ymjn=bEJZR0*Pdk`3R{;e?XZ6Fw(R5LCnGf z{vq&N0YW=25+K$Ds{5{xA@ju(>jC2d;t=nNnVFEvaw;EUZi;P6AW5bHEWmq + + + \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/timeline.xctimeline b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/timeline.xctimeline new file mode 100644 index 0000000000..bf468afeca --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift new file mode 100644 index 0000000000..420b23071b --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift @@ -0,0 +1,103 @@ +import UIKit +import SoraUI + +final class ReferendumTimelineView: UIView { + let dotsView = UIView() + private(set) var statusesView: [BaselinedView] = [] + + private func setupLayout() { + let content = UIView.hStack( + [ + dotsView, + UIView.vStack(statusesView) + ] + ) + + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } + + override func layoutSubviews() { + super.layoutSubviews() + } + + private func updateStatuses(model: Model) { + statusesView = createStatusesView(from: model) + setNeedsLayout() + } + + private func createDots() { + let dotX = dotsView.center.x + + for statusView in statusesView { + let dotY = statusView.firstBaseline.center.y + let path = UIBezierPath( + arcCenter: .init(x: dotX, y: dotY), + radius: 6, + startAngle: 0, + endAngle: 2 * .pi, + clockwise: true + ) + } + } + + private func createStatusesView(from model: Model) -> [BaselinedView] { + model.statuses.map { status in + switch status.subtitle { + case let .date(date): + let view = MultiValueView() + view.valueTop.text = status.title + view.valueBottom.text = date + case let .interval(model): + let view = GenericMultiValueView() + view.valueTop.text = status.title + view.valueBottom.bind(viewModel: model) + return view + case .none: + let label = UILabel() + label.text = status.title + return label + } + } + } +} + +extension ReferendumTimelineView { + struct Model { + let title: String + let statuses: [Status] + + struct Status { + let title: String + let subtitle: StatusSubtitle? + let isLast: Bool + } + + enum StatusSubtitle { + case date(String) + case interval(TitleIconViewModel) + } + } + + func bind(viewModel _: Model) { + setupLayout(model: model) + } +} + +protocol BaselinedView: UIView { + var firstBaseline: UIView { get } +} + +extension GenericMultiValueView: BaselinedView { + var firstBaseline: UIView { + valueTop + } +} + +extension UILabel: BaselinedView { + var firstBaseline: UIView { + self + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift index 266a1c561e..6249ec6440 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -3,30 +3,52 @@ import UIKit final class ReferendumVotingStatusDetailsView: UIView { let statusView = ReferendumVotingStatusView() let votingProgressView = VotingProgressView() - + let ayeVotesView: VoteRowView = .create { + $0.apply(style: .init( + color: R.color.colorRedFF3A69()!, + accessoryImage: R.image.iconInfo()! + )) + } + + let nayVotesView: VoteRowView = .create { + $0.apply(style: .init( + color: R.color.colorDarkGreen()!, + accessoryImage: R.image.iconInfo()! + )) + } + + let voteButton = ButtonLargeControl() + override init(frame: CGRect) { super.init(frame: frame) - + setupLayout() } - + @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - + private func setupLayout() { let content = UIView.vStack( spacing: 16, [ statusView, - votingProgressView + votingProgressView, + UIView.vStack( + distribution: .fillEqually, + [ + ayeVotesView, + nayVotesView + ] + ), + voteButton ] ) - addSubview(content) content.snp.makeConstraints { - $0.edges.equalToSuperview() + $0.edges.equalToSuperview().inset(16) } } } @@ -35,10 +57,20 @@ extension ReferendumVotingStatusDetailsView { struct Model { let status: ReferendumVotingStatusView.Model let votingProgress: VotingProgressView.Model + let aye: VoteRowView.Model? + let nay: VoteRowView.Model? + let buttonText: String? } - + func bind(viewModel: Model) { statusView.bind(viewModel: viewModel.status) votingProgressView.bind(viewModel: viewModel.votingProgress) + viewModel.aye.map { + ayeVotesView.bind(viewModel: $0) + } + viewModel.nay.map { + nayVotesView.bind(viewModel: $0) + } + voteButton.bind(viewModel.buttonText) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift index 8e1d384d98..1188e81984 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift @@ -10,7 +10,7 @@ final class ReferendumVotingStatusView: UIView { $0.spacing = 5 $0.apply(style: .timeView) } - + override init(frame: CGRect) { super.init(frame: frame) @@ -27,11 +27,11 @@ final class ReferendumVotingStatusView: UIView { spacing: 8, [ UIView.hStack([ - statusLabel, + titleLabel, UIView(), timeView ]), - titleLabel + statusLabel ] ) addSubview(content) @@ -47,7 +47,7 @@ extension ReferendumVotingStatusView { let time: Time? let title: String? } - + struct Time: Equatable { let titleIcon: TitleIconViewModel let isUrgent: Bool @@ -60,9 +60,9 @@ extension ReferendumVotingStatusView { enum StatusKind { case positive - case neutral + case negative } - + func bind(viewModel: Model) { titleLabel.text = viewModel.title statusLabel.text = viewModel.status.name @@ -71,12 +71,12 @@ extension ReferendumVotingStatusView { switch viewModel.status.kind { case .positive: statusLabel.apply(style: .positiveStatusLabel) - case .neutral: - statusLabel.apply(style: .neutralStatusLabel) + case .negative: + statusLabel.apply(style: .negativeStatusLabel) } } - func bind(timeModel: Model.Time?) { + func bind(timeModel: Time?) { if let time = timeModel { timeView.bind(viewModel: time.titleIcon) timeView.apply(style: time.isUrgent ? .activeTimeView : .timeView) @@ -84,8 +84,8 @@ extension ReferendumVotingStatusView { timeView.bind(viewModel: nil) } } - } + private extension UILabel.Style { static let positiveStatusLabel = UILabel.Style( textColor: R.color.colorDarkGreen(), diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift new file mode 100644 index 0000000000..d14704cad0 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift @@ -0,0 +1,114 @@ +import UIKit +import SwiftUI + +final class VoteRowView: UIView { + lazy var centerView = GenericTitleValueView( + titleView: titleLabel, + valueView: valueView + ) + + private let titleLabel = UILabel(style: .rowTitle, textAlignment: .left) + + private let valueView: MultiValueView = .create { + $0.apply(style: .rowContrasted) + } + + private var leadingRectangleView: UIView = .create { + $0.layer.cornerRadius = 10 + } + + private var trailingImageView = UIImageView() + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let contentView = UIView.hStack( + alignment: .center, + distribution: .fill, + spacing: 8, + [ + leadingRectangleView, + centerView, + trailingImageView + ] + ) + contentView.setCustomSpacing(16, after: leadingRectangleView) + addSubview(contentView) + trailingImageView.snp.makeConstraints { + $0.height.width.equalTo(16) + } + leadingRectangleView.snp.makeConstraints { + $0.height.equalTo(16) + $0.width.equalTo(4) + } + contentView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } + + override var intrinsicContentSize: CGSize { + .init(width: UIView.noIntrinsicMetric, height: 44) + } +} + +extension VoteRowView { + struct Style { + var color: UIColor + var accessoryImage: UIImage + } + + func apply(style: Style) { + leadingRectangleView.backgroundColor = style.color + trailingImageView.image = style.accessoryImage + } +} + +extension VoteRowView { + struct Model { + let title: String + let votes: String + let tokens: String + } + + func bind(viewModel: Model) { + titleLabel.text = viewModel.title + valueView.valueTop.text = viewModel.votes + valueView.valueBottom.text = viewModel.tokens + } +} + +extension MultiValueView { + struct Style { + let topLabel: UILabel.Style + let bottomLabel: UILabel.Style + + static let rowContrasted = Style( + topLabel: .init( + textColor: R.color.colorWhite(), + font: .regularFootnote + ), + bottomLabel: .init( + textColor: R.color.colorWhite64(), + font: .caption1 + ) + ) + } + + func apply(style: Style) { + valueTop.apply(style: style.topLabel) + valueBottom.apply(style: style.bottomLabel) + } +} + +extension UILabel.Style { + static let rowTitle = UILabel.Style(textColor: R.color.colorWhite(), font: .regularFootnote) +} From 810c56a93eb023f559c8f20c5f56f1acbfd37398 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 13 Oct 2022 23:52:17 +0500 Subject: [PATCH 040/229] fix referendum title and index --- .../Vote/Governance/View/ReferendumInfoView.swift | 4 ++-- .../Governance/ViewModel/ReferendumsModelFactory.swift | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift index f857c04f15..be19eeeb38 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -106,7 +106,7 @@ extension ReferendumInfoView { trackImageViewModel = viewModel.track?.icon if let track = viewModel.track { - trackInformation.isHidden = false + trackNameView.isHidden = false trackNameView.iconDetailsView.detailsLabel.text = track.title @@ -123,7 +123,7 @@ extension ReferendumInfoView { animated: true ) } else { - trackInformation.isHidden = true + trackNameView.isHidden = true } numberLabel.isHidden = viewModel.referendumNumber == nil diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 9ddbb49a3f..780111b39e 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -411,19 +411,19 @@ extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { return provideApprovedReferendumCellViewModel(params: params, locale: locale) case .rejected: let statusName = Strings.governanceReferendumsStatusRejected(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .negative) + status = .init(name: statusName.uppercased(), kind: .negative) case .cancelled: let statusName = Strings.governanceReferendumsStatusCancelled(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .neutral) + status = .init(name: statusName.uppercased(), kind: .neutral) case .timedOut: let statusName = Strings.governanceReferendumsStatusTimedOut(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .neutral) + status = .init(name: statusName.uppercased(), kind: .neutral) case .killed: let statusName = Strings.governanceReferendumsStatusKilled(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .negative) + status = .init(name: statusName.uppercased(), kind: .negative) case .executed: let statusName = Strings.governanceReferendumsStatusExecuted(preferredLanguages: locale.rLanguages) - status = .init(name: statusName, kind: .positive) + status = .init(name: statusName.uppercased(), kind: .positive) } return provideCommonReferendumCellViewModel(status: status, params: params, locale: locale) From 8f21bcd8d65cdcb4cea7a4302eff568793ed354a Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 14 Oct 2022 00:08:50 +0500 Subject: [PATCH 041/229] fix executed state --- .../Operation/Gov2LocalMappingFactory.swift | 12 ++++++++++-- .../Governance/Operation/Gov2OperationFactory.swift | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index 38c4aa0fed..8261bb3fc7 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -123,10 +123,18 @@ final class Gov2LocalMappingFactory { case let .ongoing(status): return createOngoingReferendumState(from: status, index: index, additionalInfo: additionalInfo) case let .approved(status): - let model = ReferendumStateLocal.Approved(since: status.since, whenEnactment: enactmentBlock) + let state: ReferendumStateLocal + + if let enactmentBlock = enactmentBlock { + let value = ReferendumStateLocal.Approved(since: status.since, whenEnactment: enactmentBlock) + state = .approved(model: value) + } else { + state = .executed + } + return ReferendumLocal( index: UInt(index), - state: .approved(model: model), + state: state, proposer: status.submissionDeposit.who ) case let .rejected(status): diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 8d502544cc..83fbe27d74 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -19,7 +19,7 @@ final class Gov2OperationFactory { try "enactment".encode(scaleEncoder: scaleEncoder) try index.encode(scaleEncoder: scaleEncoder) - let data = scaleEncoder.encode() + let data = try scaleEncoder.encode().blake2b32() var container = encoder.singleValueContainer() try container.encode(BytesCodable(wrappedValue: data)) From 3026509779cbad5b732e5281a743441d073db1ee Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 13 Oct 2022 23:40:16 +0400 Subject: [PATCH 042/229] buldfix --- .../ReferendumDetails/View/ReferendumTimelineView.swift | 4 ---- .../View/ReferendumVotingStatusDetailsView.swift | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift index 420b23071b..0e8b0ee669 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift @@ -80,10 +80,6 @@ extension ReferendumTimelineView { case interval(TitleIconViewModel) } } - - func bind(viewModel _: Model) { - setupLayout(model: model) - } } protocol BaselinedView: UIView { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift index 6249ec6440..0bbd295d67 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -59,7 +59,7 @@ extension ReferendumVotingStatusDetailsView { let votingProgress: VotingProgressView.Model let aye: VoteRowView.Model? let nay: VoteRowView.Model? - let buttonText: String? + let buttonText: String } func bind(viewModel: Model) { @@ -71,6 +71,6 @@ extension ReferendumVotingStatusDetailsView { viewModel.nay.map { nayVotesView.bind(viewModel: $0) } - voteButton.bind(viewModel.buttonText) + voteButton.bind(title: viewModel.buttonText, details: nil) } } From 102b4450025c8ae5bf9e1ba2adbfd915e4db9317 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 14 Oct 2022 09:36:49 +0500 Subject: [PATCH 043/229] fix localization --- .../Governance/ViewModel/ReferendumsModelFactory.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 780111b39e..b853709de2 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -298,7 +298,12 @@ final class ReferendumsModelFactory { amountFormatter.value(for: locale).stringFromDecimal($0) ?? "" } ?? "" - let text = R.string.localizable.governanceReferendumsThreshold(thresholdString, targetThresholdString) + let text = R.string.localizable.governanceReferendumsThreshold( + thresholdString, + targetThresholdString, + preferredLanguages: locale.rLanguages + ) + return .init(title: text, icon: image) } From b1eb6b284032c3856336187f65cbc3e5e22fe5e4 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 14 Oct 2022 10:59:22 +0500 Subject: [PATCH 044/229] provide full details data --- novawallet.xcodeproj/project.pbxproj | 32 ++++++++++++++++++ .../ReferendumDetailsInteractor.swift | 33 ++++++++++++------- .../ReferendumDetailsProtocols.swift | 9 ++++- .../ReferendumDetailsViewFactory.swift | 2 +- .../ReferendumDetailsWireframe.swift | 29 +++++++++++++++- .../ReferendumFullDetailsPresenter.swift | 29 ++++++++++++++++ .../ReferendumFullDetailsProtocols.swift | 7 ++++ .../ReferendumFullDetailsViewController.swift | 29 ++++++++++++++++ .../ReferendumFullDetailsViewFactory.swift | 30 +++++++++++++++++ .../ReferendumFullDetailsViewLayout.swift | 12 +++++++ .../ReferendumFullDetailsWireframe.swift | 3 ++ 11 files changed, 201 insertions(+), 14 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsWireframe.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 4630fe6cea..c54cf964e8 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -40,6 +40,7 @@ 1062C095BC566A1EA8DE1C06 /* CrowdloanContributionSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C71DEF78B69F017DF460AB7 /* CrowdloanContributionSetupViewController.swift */; }; 106CC4BFC48B6BFFF31434A9 /* LedgerWalletConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BC1402B34E341312ABB378 /* LedgerWalletConfirmPresenter.swift */; }; 11C6F4CD5B167DE4E9E7F654 /* DAppPhishingWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518305BB475DE40E94DCBD5D /* DAppPhishingWireframe.swift */; }; + 1269C0103216CDBDA25A5101 /* ReferendumFullDetailsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80D934D47929D2331111AD7 /* ReferendumFullDetailsWireframe.swift */; }; 12734D7CC6ACA5B657F44519 /* DAppAddFavoriteViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73DA8D51B588486D304F1B73 /* DAppAddFavoriteViewFactory.swift */; }; 135CEEC5363BE34130958578 /* ControllerAccountConfirmationInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B8473AA386E1AD6F0F0C964 /* ControllerAccountConfirmationInteractor.swift */; }; 135E979B52DC1BD29A5FC389 /* ParaStkRedeemProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E1179D4A18F46C75B19CAC2 /* ParaStkRedeemProtocols.swift */; }; @@ -116,6 +117,7 @@ 2AFF4BA2274D1E5C00D790B4 /* UsernameSetupViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AFF4BA1274D1E5C00D790B4 /* UsernameSetupViewLayout.swift */; }; 2B0FC94B4AE9AFE9532F493F /* ReferralCrowdloanViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71285CF636B32ACD8EB5519E /* ReferralCrowdloanViewFactory.swift */; }; 2B1E63AF98584341D670FB40 /* MoonbeamTermsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDB66DA5010441586327E139 /* MoonbeamTermsViewController.swift */; }; + 2B287EEF431ED9FE9510BAA4 /* ReferendumFullDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33DFAA0EEEA7F99C6D1CF4B1 /* ReferendumFullDetailsPresenter.swift */; }; 2B682D343F75EBEB8A1E65BD /* DAppAuthSettingsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C144CEF4852B97149A1848 /* DAppAuthSettingsViewLayout.swift */; }; 2BB0D54988107FA0C484C530 /* ParaStkSelectCollatorsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BE9DEF100A373868EDD03F /* ParaStkSelectCollatorsWireframe.swift */; }; 2BBA744323AA0BF6FE53C212 /* ParaStkSelectCollatorsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20878E303E9332322655F008 /* ParaStkSelectCollatorsProtocols.swift */; }; @@ -279,6 +281,7 @@ 73B9C322A5033A4534238B25 /* AssetsSearchViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 367393F8CA6157A999F69573 /* AssetsSearchViewLayout.swift */; }; 7401E7CAEEE6890BE74ACCE1 /* CustomValidatorListViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2956D0C69019DDCDAB2EB34 /* CustomValidatorListViewLayout.swift */; }; 7489BDA1D23D8DF73E7EB9BC /* UsernameSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AD15693E21C869DE1FDD17 /* UsernameSetupWireframe.swift */; }; + 74F470AE889B0E49D9808802 /* ReferendumFullDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 369C65964F4D7E8D02EEC5EC /* ReferendumFullDetailsViewFactory.swift */; }; 7580D432F22904C8F71441FE /* ParitySignerTxScanInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72FEB9C65F32B7A4FD27C9EB /* ParitySignerTxScanInteractor.swift */; }; 7584B6DC2C7F8B2B6671908F /* ParaStkYieldBoostStopViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF58EC3A44E4DDDFB4B5C84 /* ParaStkYieldBoostStopViewLayout.swift */; }; 75DAB313623E900EC475E215 /* LedgerTxConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCBCB7C3ABB6C06CD4681D44 /* LedgerTxConfirmViewFactory.swift */; }; @@ -2156,6 +2159,7 @@ 84FFE45D28620833002432BB /* XcmTransferResolutionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FFE45C28620833002432BB /* XcmTransferResolutionService.swift */; }; 84FFE505261290830054EA63 /* NetworkInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FFE504261290830054EA63 /* NetworkInfoView.swift */; }; 85547F698B551ACD387D84E2 /* SelectValidatorsStartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E62CD2831DCF0A2D5DBB08F /* SelectValidatorsStartViewController.swift */; }; + 85600C63BB1BEC76EDFA04CB /* ReferendumFullDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C535E8504943299B3E4A8EB /* ReferendumFullDetailsViewController.swift */; }; 8582395FEF296771447439FF /* AssetsSearchWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6746DDB8F277A968E6B25332 /* AssetsSearchWireframe.swift */; }; 85A093F6055DDD2E2E9253F2 /* ControllerAccountProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F829E7F8B39EE7D977001510 /* ControllerAccountProtocols.swift */; }; 86EB789787B731691B36C827 /* OnChainTransferSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1A2F7E5E278FDCC89FE097 /* OnChainTransferSetupPresenter.swift */; }; @@ -2308,6 +2312,7 @@ 9B6CD060F0EB77C162D90D3E /* ChainAddressDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 781FA4C896AF31B4035AFB38 /* ChainAddressDetailsViewFactory.swift */; }; 9BADFCBF3AF5186094DB8D67 /* DAppTxDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB4A14C99D151B41F61F474 /* DAppTxDetailsInteractor.swift */; }; 9D5926790B055C56FB74B282 /* AccountManagementProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B5072E250B7277F605855B3 /* AccountManagementProtocols.swift */; }; + 9DED20EB20A872E682CB402A /* ReferendumFullDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F6DA24E0481A3678F2EF809 /* ReferendumFullDetailsProtocols.swift */; }; 9DFB37659A6B911A4D54623E /* AccountConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E992CCDC1D581F7E9D3F1CA /* AccountConfirmInteractor.swift */; }; 9E15912C35D50C6D738FD04C /* AccountConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5002B8FA2695F470587677D2 /* AccountConfirmProtocols.swift */; }; 9E40464B7687006B1EE75C72 /* LocksProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F9944B0577EFF25A0643FE /* LocksProtocols.swift */; }; @@ -2583,6 +2588,7 @@ E8C54C2441B78248B6067204 /* YourWalletsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E2509FEA85677165C4CCCFF /* YourWalletsViewLayout.swift */; }; E8F04B9E557AD6BD0279EA6F /* ParitySignerAddressesViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20124142C4011901EF55AAA /* ParitySignerAddressesViewLayout.swift */; }; E9625CE429290F5504728D62 /* NftListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0AFEA616FDDF846F3F3650 /* NftListWireframe.swift */; }; + EAAFB082E2BB0CA418714061 /* ReferendumFullDetailsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57CDCB8CF3D8EBE5DA7A5A30 /* ReferendumFullDetailsViewLayout.swift */; }; EB376E61CD1C39AC148DE80C /* NftListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A60B27D3A045E0DEF23775 /* NftListViewController.swift */; }; EB544E8D26ABEE4ADE2F939F /* AnalyticsRewardDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC0C84704B8876688E59FA58 /* AnalyticsRewardDetailsInteractor.swift */; }; EB5F587A71CCE1F0F86154CF /* ControllerAccountViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002A29AE58EB53E915330490 /* ControllerAccountViewFactory.swift */; }; @@ -2953,11 +2959,13 @@ 329C58A0AE09361F5ECD6D4E /* DAppSearchPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppSearchPresenter.swift; sourceTree = ""; }; 335E8C17DCB794733476AAE3 /* ParaStkStakeConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkStakeConfirmViewController.swift; sourceTree = ""; }; 336395FFC4B2104A9651A2DE /* StakingRewardPayoutsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardPayoutsViewFactory.swift; sourceTree = ""; }; + 33DFAA0EEEA7F99C6D1CF4B1 /* ReferendumFullDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsPresenter.swift; sourceTree = ""; }; 3558BD7D1B8CA1409BE74879 /* AccountManagementInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountManagementInteractor.swift; sourceTree = ""; }; 3574BADE9CF77599048C7010 /* CrowdloanContributionSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupWireframe.swift; sourceTree = ""; }; 35A4A258D911C67F875E386D /* ParaStkCollatorFiltersViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorFiltersViewController.swift; sourceTree = ""; }; 365CAE2753E7D5F9B9DB7D1F /* CustomValidatorListInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CustomValidatorListInteractor.swift; sourceTree = ""; }; 367393F8CA6157A999F69573 /* AssetsSearchViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetsSearchViewLayout.swift; sourceTree = ""; }; + 369C65964F4D7E8D02EEC5EC /* ReferendumFullDetailsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsViewFactory.swift; sourceTree = ""; }; 36AB8804B896E72AC81879C6 /* ParaStkSelectCollatorsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkSelectCollatorsPresenter.swift; sourceTree = ""; }; 36AE1C39767C4CBE3229089D /* DAppPhishingViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppPhishingViewFactory.swift; sourceTree = ""; }; 376F2C0E94A454FBBBB903F6 /* ParaStkYieldBoostStopInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStopInteractor.swift; sourceTree = ""; }; @@ -2977,12 +2985,14 @@ 3BB7BFB2477E9F3893126931 /* DAppOperationConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmViewFactory.swift; sourceTree = ""; }; 3BEEFB03BBA45F5143484398 /* ParaStkRedeemViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemViewFactory.swift; sourceTree = ""; }; 3C50BB281AD6DB3CF1493958 /* DAppOperationConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmPresenter.swift; sourceTree = ""; }; + 3C535E8504943299B3E4A8EB /* ReferendumFullDetailsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsViewController.swift; sourceTree = ""; }; 3D2A26EC9537BD4275A03272 /* OperationDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OperationDetailsPresenter.swift; sourceTree = ""; }; 3D383344BEDAEDC76A6BE2CE /* DAppTxDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsProtocols.swift; sourceTree = ""; }; 3E6E41F045986002E1E26C12 /* DAppListWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppListWireframe.swift; sourceTree = ""; }; 3E992CCDC1D581F7E9D3F1CA /* AccountConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountConfirmInteractor.swift; sourceTree = ""; }; 3F1D5849A2EBF462B32F3A9C /* ExportSeedProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ExportSeedProtocols.swift; sourceTree = ""; }; 3F47E5832513985B89D06155 /* AccountExportPasswordWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountExportPasswordWireframe.swift; sourceTree = ""; }; + 3F6DA24E0481A3678F2EF809 /* ReferendumFullDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsProtocols.swift; sourceTree = ""; }; 3F7068913923A6DEEE9D8EA0 /* CrowdloanContributionSetupPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupPresenter.swift; sourceTree = ""; }; 3F75722D2F921FD1C2D4105D /* CrowdloanContributionConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmViewController.swift; sourceTree = ""; }; 3FECFFBAB264397F9B2646CE /* ChangeWatchOnlyViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChangeWatchOnlyViewController.swift; sourceTree = ""; }; @@ -3037,6 +3047,7 @@ 57535268534B154B42ED51CE /* MessageSheetViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MessageSheetViewFactory.swift; sourceTree = ""; }; 578743E9101B334BFBE44CB6 /* ParaStkRedeemWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemWireframe.swift; sourceTree = ""; }; 57C624E71FCE0FFF8EAD5BA9 /* RecommendedValidatorListWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RecommendedValidatorListWireframe.swift; sourceTree = ""; }; + 57CDCB8CF3D8EBE5DA7A5A30 /* ReferendumFullDetailsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsViewLayout.swift; sourceTree = ""; }; 58612684146AD03AD7BC30DF /* ChangeWatchOnlyViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChangeWatchOnlyViewLayout.swift; sourceTree = ""; }; 594BC61689EC942ED0A64A4A /* ReferralCrowdloanViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferralCrowdloanViewLayout.swift; sourceTree = ""; }; 597A3C3F2937333D0EC7ABD5 /* AdvancedWalletViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AdvancedWalletViewController.swift; sourceTree = ""; }; @@ -5343,6 +5354,7 @@ C503100478AB56E903598A78 /* ReferralCrowdloanPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferralCrowdloanPresenter.swift; sourceTree = ""; }; C6F8BBBA9EABA266B288333F /* AnalyticsValidatorsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsValidatorsViewFactory.swift; sourceTree = ""; }; C74A2166B054240BD5D925B6 /* UsernameSetupViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UsernameSetupViewFactory.swift; sourceTree = ""; }; + C80D934D47929D2331111AD7 /* ReferendumFullDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsWireframe.swift; sourceTree = ""; }; C96C3B5ABF4A8124848EFD17 /* ControllerAccountConfirmationWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ControllerAccountConfirmationWireframe.swift; sourceTree = ""; }; C9978451AB2F4958E6FF117D /* YourWalletsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourWalletsViewFactory.swift; sourceTree = ""; }; CAB80E4CA0D5FA56612318A2 /* ChangeWatchOnlyProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChangeWatchOnlyProtocols.swift; sourceTree = ""; }; @@ -8394,6 +8406,7 @@ 84D8753B28EB1796004065BD /* Model */, 8442002128E6FE0100C49C4A /* Referendums */, B4F0332763AFF64A3793C679 /* ReferendumDetails */, + 872D923BC3CE0F69157DB2EA /* ReferendumFullDetails */, ); path = Governance; sourceTree = ""; @@ -11857,6 +11870,19 @@ path = ParaStkUnstakeConfirm; sourceTree = ""; }; + 872D923BC3CE0F69157DB2EA /* ReferendumFullDetails */ = { + isa = PBXGroup; + children = ( + 3F6DA24E0481A3678F2EF809 /* ReferendumFullDetailsProtocols.swift */, + C80D934D47929D2331111AD7 /* ReferendumFullDetailsWireframe.swift */, + 33DFAA0EEEA7F99C6D1CF4B1 /* ReferendumFullDetailsPresenter.swift */, + 3C535E8504943299B3E4A8EB /* ReferendumFullDetailsViewController.swift */, + 57CDCB8CF3D8EBE5DA7A5A30 /* ReferendumFullDetailsViewLayout.swift */, + 369C65964F4D7E8D02EEC5EC /* ReferendumFullDetailsViewFactory.swift */, + ); + path = ReferendumFullDetails; + sourceTree = ""; + }; 880059D628EEA55500E87B9B /* View */ = { isa = PBXGroup; children = ( @@ -16477,6 +16503,12 @@ 845B811D28F44A700040CE84 /* ReferendumActionLocal.swift in Sources */, 3403F3DCDE932B9F9C6D32B6 /* ReferendumDetailsViewLayout.swift in Sources */, 1A029717AD309487B70FFD02 /* ReferendumDetailsViewFactory.swift in Sources */, + 9DED20EB20A872E682CB402A /* ReferendumFullDetailsProtocols.swift in Sources */, + 1269C0103216CDBDA25A5101 /* ReferendumFullDetailsWireframe.swift in Sources */, + 2B287EEF431ED9FE9510BAA4 /* ReferendumFullDetailsPresenter.swift in Sources */, + 85600C63BB1BEC76EDFA04CB /* ReferendumFullDetailsViewController.swift in Sources */, + EAAFB082E2BB0CA418714061 /* ReferendumFullDetailsViewLayout.swift in Sources */, + 74F470AE889B0E49D9808802 /* ReferendumFullDetailsViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 1fd6262c7f..e3befad77d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -6,6 +6,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { weak var presenter: ReferendumDetailsInteractorOutputProtocol? private(set) var referendum: ReferendumLocal + private(set) var actionDetails: ReferendumActionLocal? let chain: ChainModel let actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol let connection: JSONRPCEngine @@ -135,21 +136,27 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { } private func provideIdentities() { - guard let proposer = referendum.proposer else { - presenter?.didReceiveIdentities([:]) - return + clear(cancellable: &identitiesCancellable) + + var accountIds: [AccountId] = [] + + if let proposer = referendum.proposer { + accountIds.append(proposer) } - guard identitiesCancellable == nil else { - return + if let beneficiary = actionDetails?.amountSpendDetails?.beneficiaryAccountId { + accountIds.append(beneficiary) } - let accountIds: () throws -> [AccountId] = { - [proposer] + guard !accountIds.isEmpty else { + presenter?.didReceiveIdentities([:]) + return } + let accountIdsClosure: () throws -> [AccountId] = { accountIds } + let wrapper = identityOperationFactory.createIdentityWrapper( - for: accountIds, + for: accountIdsClosure, engine: connection, runtimeService: runtimeProvider, chainFormat: chain.chainFormat @@ -206,7 +213,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { operationQueue.addOperation(operation) } - private func provideActionDetails() { + private func updateActionDetails() { guard actionDetailsCancellable == nil else { return } @@ -227,7 +234,11 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { do { let actionDetails = try wrapper.targetOperation.extractNoCancellableResultData() + self?.actionDetails = actionDetails + self?.presenter?.didReceiveActionDetails(actionDetails) + + self?.provideIdentities() } catch { self?.presenter?.didReceiveError(.actionDetailsFailed(error)) } @@ -251,7 +262,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol { func setup() { makeSubscriptions() - provideActionDetails() + updateActionDetails() provideIdentities() } @@ -260,7 +271,7 @@ extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol } func refreshActionDetails() { - provideActionDetails() + updateActionDetails() } func refreshIdentities() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 7f396f4668..cc34057ebc 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -23,4 +23,11 @@ protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { func didReceiveError(_ error: ReferendumDetailsInteractorError) } -protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable {} +protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable { + func showFullDetails( + from view: ReferendumDetailsViewProtocol?, + referendum: ReferendumLocal, + actionDetails: ReferendumActionLocal, + identities: [AccountAddress: AccountIdentity] + ) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 569a0548db..2655152085 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -18,7 +18,7 @@ struct ReferendumDetailsViewFactory { return nil } - let wireframe = ReferendumDetailsWireframe() + let wireframe = ReferendumDetailsWireframe(state: state) let localizationManager = LocalizationManager.shared diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index bb3b48abd9..43d65b9776 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -1,3 +1,30 @@ import Foundation -final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol {} +final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { + let state: GovernanceSharedState + + init(state: GovernanceSharedState) { + self.state = state + } + + func showFullDetails( + from view: ReferendumDetailsViewProtocol?, + referendum: ReferendumLocal, + actionDetails: ReferendumActionLocal, + identities: [AccountAddress: AccountIdentity] + ) { + guard + let fullDetailsView = ReferendumFullDetailsViewFactory.createView( + state: state, + referendum: referendum, + actionDetails: actionDetails, + identities: identities + ) else { + return + } + + let navigationController = FearlessNavigationController(rootViewController: fullDetailsView.controller) + + view?.controller.present(navigationController, animated: true) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift new file mode 100644 index 0000000000..512d64548f --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -0,0 +1,29 @@ +import Foundation + +final class ReferendumFullDetailsPresenter { + weak var view: ReferendumFullDetailsViewProtocol? + let wireframe: ReferendumFullDetailsWireframeProtocol + + let chain: ChainModel + let referendum: ReferendumLocal + let actionDetails: ReferendumActionLocal + let identities: [AccountAddress: AccountIdentity] + + init( + wireframe: ReferendumFullDetailsWireframeProtocol, + chain: ChainModel, + referendum: ReferendumLocal, + actionDetails: ReferendumActionLocal, + identities: [AccountAddress: AccountIdentity] + ) { + self.wireframe = wireframe + self.chain = chain + self.referendum = referendum + self.actionDetails = actionDetails + self.identities = identities + } +} + +extension ReferendumFullDetailsPresenter: ReferendumFullDetailsPresenterProtocol { + func setup() {} +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift new file mode 100644 index 0000000000..e11b42985f --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift @@ -0,0 +1,7 @@ +protocol ReferendumFullDetailsViewProtocol: ControllerBackedProtocol {} + +protocol ReferendumFullDetailsPresenterProtocol: AnyObject { + func setup() +} + +protocol ReferendumFullDetailsWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift new file mode 100644 index 0000000000..c9e80267d6 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift @@ -0,0 +1,29 @@ +import UIKit + +final class ReferendumFullDetailsViewController: UIViewController { + typealias RootViewType = ReferendumFullDetailsViewLayout + + let presenter: ReferendumFullDetailsPresenterProtocol + + init(presenter: ReferendumFullDetailsPresenterProtocol) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = ReferendumFullDetailsViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + presenter.setup() + } +} + +extension ReferendumFullDetailsViewController: ReferendumFullDetailsViewProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift new file mode 100644 index 0000000000..bf3e319b87 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift @@ -0,0 +1,30 @@ +import Foundation + +struct ReferendumFullDetailsViewFactory { + static func createView( + state: GovernanceSharedState, + referendum: ReferendumLocal, + actionDetails: ReferendumActionLocal, + identities: [AccountAddress: AccountIdentity] + ) -> ReferendumFullDetailsViewProtocol? { + guard let chain = state.settings.value else { + return nil + } + + let wireframe = ReferendumFullDetailsWireframe() + + let presenter = ReferendumFullDetailsPresenter( + wireframe: wireframe, + chain: chain, + referendum: referendum, + actionDetails: actionDetails, + identities: identities + ) + + let view = ReferendumFullDetailsViewController(presenter: presenter) + + presenter.view = view + + return view + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift new file mode 100644 index 0000000000..46b36a5de4 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -0,0 +1,12 @@ +import UIKit + +final class ReferendumFullDetailsViewLayout: UIView { + override init(frame: CGRect) { + super.init(frame: frame) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsWireframe.swift new file mode 100644 index 0000000000..d6a6aed886 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class ReferendumFullDetailsWireframe: ReferendumFullDetailsWireframeProtocol {} From 3626e24b1743df80eefbc7b853cc0a222f728404 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 14 Oct 2022 12:43:45 +0500 Subject: [PATCH 045/229] add referendum voters interactor --- novawallet.xcodeproj/project.pbxproj | 56 ++++++++++++ .../ReferendumVotersInteractorError.swift | 5 ++ .../Model/ReferendumVotersModel.swift | 6 ++ .../Model/ReferendumVotersType.swift | 6 ++ .../ReferendumVotersInteractor.swift | 87 +++++++++++++++++++ .../ReferendumVotersPresenter.swift | 21 +++++ .../ReferendumVotersProtocols.swift | 17 ++++ .../ReferendumVotersViewController.swift | 29 +++++++ .../ReferendumVotersViewFactory.swift | 21 +++++ .../ReferendumVotersViewLayout.swift | 13 +++ .../ReferendumVotersWireframe.swift | 3 + 11 files changed, 264 insertions(+) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersInteractorError.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersModel.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersType.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersWireframe.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index c54cf964e8..9fbbe574a1 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 003063A17B04BA6327EA355F /* ReferendumVotersProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6FE9E98CB265815986BE909 /* ReferendumVotersProtocols.swift */; }; 006BEDBD2F98FF54DB993D8C /* DAppAddFavoriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057EF626183878DD2C9E7BC7 /* DAppAddFavoriteViewController.swift */; }; 0119531FAE0D22EA9464F84D /* ParaStkYourCollatorsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 128EA612020D98F3B0D0FA96 /* ParaStkYourCollatorsProtocols.swift */; }; 012AE9F8BDA682C691B6F9FD /* ParitySignerWelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CF6E3E64F7608EF6C28399 /* ParitySignerWelcomeViewController.swift */; }; @@ -56,6 +57,7 @@ 19A29027666EB5388CBFAD61 /* StakingRewardDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D613E20E96E7BA5B8F4B9799 /* StakingRewardDetailsInteractor.swift */; }; 19D3739A3C7800A5A18DA41C /* LedgerNetworkSelectionInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56C015A20B918DF75C499FFF /* LedgerNetworkSelectionInteractor.swift */; }; 1A029717AD309487B70FFD02 /* ReferendumDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2F90150AD2DD3CDF7F4EDA /* ReferendumDetailsViewFactory.swift */; }; + 1A3608A12079F00796FA9718 /* ReferendumVotersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42594560B2928C79B87275D8 /* ReferendumVotersViewController.swift */; }; 1B1402BB29CFF6D9FB944B2D /* CreateWatchOnlyViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9DD724F02DA0A174D875A8 /* CreateWatchOnlyViewLayout.swift */; }; 1BEADE77C6236CB3BF719A47 /* CrowdloanContributionSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C96E41F878ED0A0A6F469D3 /* CrowdloanContributionSetupViewFactory.swift */; }; 1BFC90E1D8646F7429FFD5E6 /* ExportMnemonicProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF3AD755B2B3DCFB3D14DF91 /* ExportMnemonicProtocols.swift */; }; @@ -193,6 +195,7 @@ 4B4189889DEFAF917332D41C /* ChangeWatchOnlyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FECFFBAB264397F9B2646CE /* ChangeWatchOnlyViewController.swift */; }; 4BC33C8DE172AE573AEEDA4F /* WalletsListProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8FC21B4670E7B22B787357D /* WalletsListProtocols.swift */; }; 4C165167688A2791643AC667 /* LedgerDiscoverProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1A9B9D741BABBCE6C70BE45 /* LedgerDiscoverProtocols.swift */; }; + 4D44B178F1F57FD8607E8095 /* ReferendumVotersViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8602E65CC4E81A7BE1727CE3 /* ReferendumVotersViewLayout.swift */; }; 4E184FFD1532C293BDF6D7C1 /* DAppAuthSettingsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EE72F2B6612508D4783A507 /* DAppAuthSettingsProtocols.swift */; }; 4E262D60ACAF44A1FD18FD1D /* TransferConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF34514F17CE47AF0C5A66F6 /* TransferConfirmWireframe.swift */; }; 4E5CD7B8821FA5298EA1598E /* CrowdloanContributionSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3574BADE9CF77599048C7010 /* CrowdloanContributionSetupWireframe.swift */; }; @@ -1213,6 +1216,9 @@ 8482F62F280C618B0006C3A0 /* DAppAuthSettingsTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8482F62E280C618B0006C3A0 /* DAppAuthSettingsTableCell.swift */; }; 8482F63128101FB10006C3A0 /* DAppEthereumSignBytesInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8482F63028101FB10006C3A0 /* DAppEthereumSignBytesInteractor.swift */; }; 8482F633281024B80006C3A0 /* Data+EthereumSign.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8482F632281024B80006C3A0 /* Data+EthereumSign.swift */; }; + 8483B15128F93A080048B295 /* ReferendumVotersType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15028F93A080048B295 /* ReferendumVotersType.swift */; }; + 8483B15328F940080048B295 /* ReferendumVotersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15228F940080048B295 /* ReferendumVotersModel.swift */; }; + 8483B15528F9406C0048B295 /* ReferendumVotersInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15428F9406C0048B295 /* ReferendumVotersInteractorError.swift */; }; 8485D924277E16C400767243 /* DAppBrowserScriptHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */; }; 84873AFF26028E2B000A83EE /* StakingStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */; }; 84873B0426029B75000A83EE /* StakingEstimationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */; }; @@ -2263,6 +2269,7 @@ 88F7716028BEA589008C028A /* YourWalletsIconDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7715F28BEA589008C028A /* YourWalletsIconDetailsView.swift */; }; 88F7716428BF6B59008C028A /* GenericMultiValueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7716328BF6B59008C028A /* GenericMultiValueView.swift */; }; 8916E9179CF5409E65D1B3A6 /* NftDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A46EE888D60C1538A0A3EFC /* NftDetailsProtocols.swift */; }; + 89724EA9F732D0C967253597 /* ReferendumVotersViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF3C1CFECE4340E82837FC4 /* ReferendumVotersViewFactory.swift */; }; 8A19EC93E6A6972327116D80 /* ParaStkStakeConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1139FB38E7D8D25A36726089 /* ParaStkStakeConfirmProtocols.swift */; }; 8A23DD1F4146639EA2F7AEF6 /* LocksViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81B239BD9C150BFE9A82B0 /* LocksViewFactory.swift */; }; 8AEF593AFE8F59F7DC0A5753 /* CustomValidatorListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 365CAE2753E7D5F9B9DB7D1F /* CustomValidatorListInteractor.swift */; }; @@ -2284,6 +2291,7 @@ 91A1286763617DE022BD495F /* LedgerInstructionsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B08ACC71BE679A48A7B66E /* LedgerInstructionsPresenter.swift */; }; 921E4891E85C0DC6FDD8A0D0 /* CrowdloanContributionConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1366336078BCA34EFB4C6FF9 /* CrowdloanContributionConfirmInteractor.swift */; }; 93434E8E407A6C63D8862A21 /* AssetSelectionProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DECC58C93DB18E79A03B5A0 /* AssetSelectionProtocols.swift */; }; + 93EB8C73108944E9C576936C /* ReferendumVotersPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9990DF2F0214CD51E5388CE /* ReferendumVotersPresenter.swift */; }; 940DA38E4586A27D7F3E0C67 /* ParitySignerAddressesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3280014154DCC105757E317C /* ParitySignerAddressesViewController.swift */; }; 94B0F0C84AF74B3CD7223C3A /* AccountConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7306D50F278F6CC90DC88F27 /* AccountConfirmPresenter.swift */; }; 94B234EE404088B077DB6411 /* DAppListProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10F3CCA5BA57C68D5AE2B42F /* DAppListProtocols.swift */; }; @@ -2577,6 +2585,7 @@ E325FBFE10A037E58525DA66 /* DAppSearchViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF9C192200F9B998724FC6C /* DAppSearchViewFactory.swift */; }; E36D8899C003C0AFA5BE290F /* AssetsManageProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90681A889A40F7163CBE9B6B /* AssetsManageProtocols.swift */; }; E37BB7A393FFEFC350B4EA3D /* AdvancedWalletProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0043E77B2DBB3546A9E54C4B /* AdvancedWalletProtocols.swift */; }; + E4021A6E90432CC5C797A647 /* ReferendumVotersWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9FBF368FBB46AD4DE606DB1 /* ReferendumVotersWireframe.swift */; }; E477B09B47A3021EF1CE66F0 /* ParaStkRedeemViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D3F02FD57B4C28BA09C5F8 /* ParaStkRedeemViewLayout.swift */; }; E488F3E052650FF525D41D63 /* LedgerTxConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 313B89948DC631DE61E01007 /* LedgerTxConfirmInteractor.swift */; }; E5DC2660D78D3CC9FC48E748 /* LedgerAccountConfirmationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A04CDB05A013ED57D3DEA3 /* LedgerAccountConfirmationViewController.swift */; }; @@ -2617,6 +2626,7 @@ F20C8D17ABF18B7104E14394 /* StakingAmountInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 312DE7ADA5ABC3214AD3D4AD /* StakingAmountInteractor.swift */; }; F27AAD7BC84793FA63027F8C /* AssetsManageInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA134C6DB56DE1DFBA1B88B4 /* AssetsManageInteractor.swift */; }; F382BF4F8C3C46C7C21DE5C0 /* ParaStkUnstakeConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86DCB6F3977BDE1BDC7BC3F9 /* ParaStkUnstakeConfirmPresenter.swift */; }; + F3BB50CCA38C9B47FDBEDF53 /* ReferendumVotersInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23CC3812E4DFC26484324D57 /* ReferendumVotersInteractor.swift */; }; F3D2AC37709EAF088A594B73 /* AccountManagementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FCA2DD3A8898D64CBC9F97 /* AccountManagementViewController.swift */; }; F400A7C2260CE1670061D576 /* StakingRewardStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = F400A7C1260CE1670061D576 /* StakingRewardStatus.swift */; }; F402BC83273ACDC30075F803 /* AstarBonusService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F402BC82273ACDC30075F803 /* AstarBonusService.swift */; }; @@ -2898,6 +2908,7 @@ 2377F8FB07B47637346249F5 /* StakingRewardDetailsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardDetailsViewFactory.swift; sourceTree = ""; }; 23A74BDB54D503FA2BFBEF35 /* StakingUnbondSetupProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondSetupProtocols.swift; sourceTree = ""; }; 23BC71941B91D3E372CDB11C /* CrowdloanContributionSetupViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupViewLayout.swift; sourceTree = ""; }; + 23CC3812E4DFC26484324D57 /* ReferendumVotersInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVotersInteractor.swift; sourceTree = ""; }; 245DED717B5B3FC380C24E3D /* ChainAddressDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainAddressDetailsWireframe.swift; sourceTree = ""; }; 24B23BAD22C87DA5F324B44F /* DAppAuthSettingsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthSettingsWireframe.swift; sourceTree = ""; }; 256215C11DC0E091660034EA /* CrowdloanYourContributionsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanYourContributionsViewController.swift; sourceTree = ""; }; @@ -3000,6 +3011,7 @@ 40B47961B2254E8A4D8EC588 /* StakingAmountPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingAmountPresenter.swift; sourceTree = ""; }; 4191E0055768541F6A3D8A61 /* StakingRewardPayoutsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardPayoutsInteractor.swift; sourceTree = ""; }; 41DFB2757D029FB5DF3CEBC2 /* WalletHistoryFilterProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletHistoryFilterProtocols.swift; sourceTree = ""; }; + 42594560B2928C79B87275D8 /* ReferendumVotersViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVotersViewController.swift; sourceTree = ""; }; 43AE3AE09F98E37C15BA87A1 /* LedgerInstructionsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerInstructionsWireframe.swift; sourceTree = ""; }; 43FBC2EA83A121CEBD25549D /* DAppOperationConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmViewController.swift; sourceTree = ""; }; 44809BCF44D7329266A60A9D /* ParitySignerAddConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddConfirmInteractor.swift; sourceTree = ""; }; @@ -4047,6 +4059,9 @@ 8482F62E280C618B0006C3A0 /* DAppAuthSettingsTableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppAuthSettingsTableCell.swift; sourceTree = ""; }; 8482F63028101FB10006C3A0 /* DAppEthereumSignBytesInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppEthereumSignBytesInteractor.swift; sourceTree = ""; }; 8482F632281024B80006C3A0 /* Data+EthereumSign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+EthereumSign.swift"; sourceTree = ""; }; + 8483B15028F93A080048B295 /* ReferendumVotersType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotersType.swift; sourceTree = ""; }; + 8483B15228F940080048B295 /* ReferendumVotersModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotersModel.swift; sourceTree = ""; }; + 8483B15428F9406C0048B295 /* ReferendumVotersInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotersInteractorError.swift; sourceTree = ""; }; 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserScriptHandler.swift; sourceTree = ""; }; 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingStateMachine.swift; sourceTree = ""; }; 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingEstimationViewModel.swift; sourceTree = ""; }; @@ -5005,6 +5020,7 @@ 859E0EF774DF0D498FEF8FCB /* DAppOperationConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmViewLayout.swift; sourceTree = ""; }; 85D8B7BE70A9F907F8B43BFC /* TransferSetupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TransferSetupViewController.swift; sourceTree = ""; }; 85F45A5C6145F863760F4409 /* AccountImportWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountImportWireframe.swift; sourceTree = ""; }; + 8602E65CC4E81A7BE1727CE3 /* ReferendumVotersViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVotersViewLayout.swift; sourceTree = ""; }; 86DCB6F3977BDE1BDC7BC3F9 /* ParaStkUnstakeConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeConfirmPresenter.swift; sourceTree = ""; }; 86F7A369E31DCB9ABD556EE9 /* CrowdloanListPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanListPresenter.swift; sourceTree = ""; }; 86F9063B2DF46E7B65B5248E /* Pods_novawalletAll_novawalletIntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_novawalletAll_novawalletIntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -5357,6 +5373,7 @@ C80D934D47929D2331111AD7 /* ReferendumFullDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsWireframe.swift; sourceTree = ""; }; C96C3B5ABF4A8124848EFD17 /* ControllerAccountConfirmationWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ControllerAccountConfirmationWireframe.swift; sourceTree = ""; }; C9978451AB2F4958E6FF117D /* YourWalletsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourWalletsViewFactory.swift; sourceTree = ""; }; + C9990DF2F0214CD51E5388CE /* ReferendumVotersPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVotersPresenter.swift; sourceTree = ""; }; CAB80E4CA0D5FA56612318A2 /* ChangeWatchOnlyProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChangeWatchOnlyProtocols.swift; sourceTree = ""; }; CB441F15E16B07196DD9CE9D /* ParaStkUnstakeProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeProtocols.swift; sourceTree = ""; }; CB9150FEC66FC503CF1BD1D0 /* WalletHistoryFilterPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletHistoryFilterPresenter.swift; sourceTree = ""; }; @@ -5409,6 +5426,7 @@ DBFC5052A062548D20D232DA /* AssetsManageWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetsManageWireframe.swift; sourceTree = ""; }; DD1A2F7E5E278FDCC89FE097 /* OnChainTransferSetupPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OnChainTransferSetupPresenter.swift; sourceTree = ""; }; DD2F1EEBF48485F02BF690A4 /* ParaStkStakeSetupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkStakeSetupViewController.swift; sourceTree = ""; }; + DDF3C1CFECE4340E82837FC4 /* ReferendumVotersViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVotersViewFactory.swift; sourceTree = ""; }; DF715CEF29477B59119520F1 /* ParitySignerAddressesInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddressesInteractor.swift; sourceTree = ""; }; DFF58EC3A44E4DDDFB4B5C84 /* ParaStkYieldBoostStopViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStopViewLayout.swift; sourceTree = ""; }; E0DB5EA5195D9433A4B90793 /* AdvancedWalletWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AdvancedWalletWireframe.swift; sourceTree = ""; }; @@ -5428,10 +5446,12 @@ E5CC1FB277A878E9C9B7EAEB /* AccountImportInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountImportInteractor.swift; sourceTree = ""; }; E63ECD1205B2CCCDA2E66A1E /* ParaStkYieldBoostSetupViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostSetupViewLayout.swift; sourceTree = ""; }; E675B4C5BE36C0004564105B /* DAppOperationConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmProtocols.swift; sourceTree = ""; }; + E6FE9E98CB265815986BE909 /* ReferendumVotersProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVotersProtocols.swift; sourceTree = ""; }; E8B10C37813EFE7D7663605E /* ParitySignerAddressesWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddressesWireframe.swift; sourceTree = ""; }; E8C13B77688FFF0FFBBB6612 /* ParaStkYourCollatorsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYourCollatorsWireframe.swift; sourceTree = ""; }; E9636093217ABE05A7FAC9B9 /* AccountCreateViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountCreateViewFactory.swift; sourceTree = ""; }; E9F49B3B261FBA0B568A5320 /* ParaStkRebondPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRebondPresenter.swift; sourceTree = ""; }; + E9FBF368FBB46AD4DE606DB1 /* ReferendumVotersWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVotersWireframe.swift; sourceTree = ""; }; EB8605FD90D8C3553A9897B4 /* AccountImportPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountImportPresenter.swift; sourceTree = ""; }; ED010772D7CE0450BDF30707 /* ParaStkCollatorFiltersViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorFiltersViewFactory.swift; sourceTree = ""; }; ED5CED3C58CD433B19978EC4 /* TransferOnChainConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TransferOnChainConfirmInteractor.swift; sourceTree = ""; }; @@ -6117,6 +6137,21 @@ path = HistoryFilter; sourceTree = ""; }; + 357F2FABE25DB08B50B329CF /* ReferendumVoters */ = { + isa = PBXGroup; + children = ( + 8483B14F28F939F30048B295 /* Model */, + E6FE9E98CB265815986BE909 /* ReferendumVotersProtocols.swift */, + E9FBF368FBB46AD4DE606DB1 /* ReferendumVotersWireframe.swift */, + C9990DF2F0214CD51E5388CE /* ReferendumVotersPresenter.swift */, + 23CC3812E4DFC26484324D57 /* ReferendumVotersInteractor.swift */, + 42594560B2928C79B87275D8 /* ReferendumVotersViewController.swift */, + 8602E65CC4E81A7BE1727CE3 /* ReferendumVotersViewLayout.swift */, + DDF3C1CFECE4340E82837FC4 /* ReferendumVotersViewFactory.swift */, + ); + path = ReferendumVoters; + sourceTree = ""; + }; 39A771F6D252031C00568966 /* ParaStkYieldBoostSetup */ = { isa = PBXGroup; children = ( @@ -8407,6 +8442,7 @@ 8442002128E6FE0100C49C4A /* Referendums */, B4F0332763AFF64A3793C679 /* ReferendumDetails */, 872D923BC3CE0F69157DB2EA /* ReferendumFullDetails */, + 357F2FABE25DB08B50B329CF /* ReferendumVoters */, ); path = Governance; sourceTree = ""; @@ -8488,6 +8524,16 @@ path = View; sourceTree = ""; }; + 8483B14F28F939F30048B295 /* Model */ = { + isa = PBXGroup; + children = ( + 8483B15028F93A080048B295 /* ReferendumVotersType.swift */, + 8483B15228F940080048B295 /* ReferendumVotersModel.swift */, + 8483B15428F9406C0048B295 /* ReferendumVotersInteractorError.swift */, + ); + path = Model; + sourceTree = ""; + }; 8487582227F06AF300495306 /* QRScanner */ = { isa = PBXGroup; children = ( @@ -16077,6 +16123,7 @@ 8487583C27F06AF300495306 /* QRCaptureService.swift in Sources */, 7D707DDD180999C63FD0C4ED /* AssetListViewController.swift in Sources */, 75E689BC8D16786DF2674171 /* AssetListViewLayout.swift in Sources */, + 8483B15328F940080048B295 /* ReferendumVotersModel.swift in Sources */, 2736BAABAE1389260A0B28D6 /* AssetListViewFactory.swift in Sources */, 88E1E896289C021F00C123A8 /* CurrencyCollectionViewCell.swift in Sources */, BE8CF97B6EA62C75277B78AA /* MoonbeamTermsProtocols.swift in Sources */, @@ -16145,6 +16192,7 @@ 8892284A28F35410003F8B9E /* ReferendumsViewModel.swift in Sources */, E2A9BC1477D81DDDE519404C /* DAppOperationConfirmWireframe.swift in Sources */, 88D997AE28AB86FE006135A5 /* YourContributionsView.swift in Sources */, + 8483B15128F93A080048B295 /* ReferendumVotersType.swift in Sources */, 84ED6BDE28688CA500B3C558 /* TransferNetworkContainerView.swift in Sources */, 849976CE27B3921800B14A6C /* DAppMetamaskAuthorizedState.swift in Sources */, 8445F41328C8C6E0009E61C4 /* ParaStkYieldBoostInitState.swift in Sources */, @@ -16248,6 +16296,7 @@ 84FFE45D28620833002432BB /* XcmTransferResolutionService.swift in Sources */, D3F199376DAEBF380C5FFD9D /* DAppAddFavoriteViewLayout.swift in Sources */, 12734D7CC6ACA5B657F44519 /* DAppAddFavoriteViewFactory.swift in Sources */, + 8483B15528F9406C0048B295 /* ReferendumVotersInteractorError.swift in Sources */, 4E184FFD1532C293BDF6D7C1 /* DAppAuthSettingsProtocols.swift in Sources */, 319124D11B1376B430B6C2EF /* DAppAuthSettingsWireframe.swift in Sources */, EBC1107125C55A65D4E21417 /* DAppAuthSettingsPresenter.swift in Sources */, @@ -16509,6 +16558,13 @@ 85600C63BB1BEC76EDFA04CB /* ReferendumFullDetailsViewController.swift in Sources */, EAAFB082E2BB0CA418714061 /* ReferendumFullDetailsViewLayout.swift in Sources */, 74F470AE889B0E49D9808802 /* ReferendumFullDetailsViewFactory.swift in Sources */, + 003063A17B04BA6327EA355F /* ReferendumVotersProtocols.swift in Sources */, + E4021A6E90432CC5C797A647 /* ReferendumVotersWireframe.swift in Sources */, + 93EB8C73108944E9C576936C /* ReferendumVotersPresenter.swift in Sources */, + F3BB50CCA38C9B47FDBEDF53 /* ReferendumVotersInteractor.swift in Sources */, + 1A3608A12079F00796FA9718 /* ReferendumVotersViewController.swift in Sources */, + 4D44B178F1F57FD8607E8095 /* ReferendumVotersViewLayout.swift in Sources */, + 89724EA9F732D0C967253597 /* ReferendumVotersViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersInteractorError.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersInteractorError.swift new file mode 100644 index 0000000000..f166fc101e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersInteractorError.swift @@ -0,0 +1,5 @@ +import Foundation + +enum ReferendumVotersInteractorError: Error { + case votersFetchFailed(_ internalError: Error) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersModel.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersModel.swift new file mode 100644 index 0000000000..874340ca8e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersModel.swift @@ -0,0 +1,6 @@ +import Foundation + +struct ReferendumVotersModel { + let voters: [ReferendumVoterLocal] + let identites: [AccountAddress: AccountIdentity] +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersType.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersType.swift new file mode 100644 index 0000000000..c6decefef4 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/Model/ReferendumVotersType.swift @@ -0,0 +1,6 @@ +import Foundation + +enum ReferendumVotersType { + case ayes + case nays +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift new file mode 100644 index 0000000000..eaabaef4f2 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift @@ -0,0 +1,87 @@ +import UIKit +import SubstrateSdk +import RobinHood + +final class ReferendumVotersInteractor { + weak var presenter: ReferendumVotersInteractorOutputProtocol? + + let referendumsOperationFactory: ReferendumsOperationFactoryProtocol + let chain: ChainModel + let referendumIndex: Referenda.ReferendumIndex + let identityOperationFactory: IdentityOperationFactoryProtocol + let connection: JSONRPCEngine + let runtimeProvider: RuntimeProviderProtocol + let operationQueue: OperationQueue + + init( + referendumIndex: Referenda.ReferendumIndex, + chain: ChainModel, + referendumsOperationFactory: ReferendumsOperationFactoryProtocol, + identityOperationFactory: IdentityOperationFactoryProtocol, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + operationQueue: OperationQueue + ) { + self.referendumIndex = referendumIndex + self.chain = chain + self.referendumsOperationFactory = referendumsOperationFactory + self.identityOperationFactory = identityOperationFactory + self.connection = connection + self.runtimeProvider = runtimeProvider + self.operationQueue = operationQueue + } + + private func provideVoters() { + let voterWrapper = referendumsOperationFactory.fetchVotersWrapper( + for: referendumIndex, + from: connection, + runtimeProvider: runtimeProvider + ) + + let identityWrapper = identityOperationFactory.createIdentityWrapper( + for: { + let voters = try voterWrapper.targetOperation.extractNoCancellableResultData() + return voters.map { $0.accountId } + }, + engine: connection, + runtimeService: runtimeProvider, + chainFormat: chain.chainFormat + ) + + identityWrapper.addDependency(wrapper: voterWrapper) + + let mappingOperation = ClosureOperation { + let voters = try voterWrapper.targetOperation.extractNoCancellableResultData() + let identities = try identityWrapper.targetOperation.extractNoCancellableResultData() + + return ReferendumVotersModel(voters: voters, identites: identities) + } + + mappingOperation.addDependency(identityWrapper.targetOperation) + + mappingOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + do { + let model = try mappingOperation.extractNoCancellableResultData() + self?.presenter?.didReceiveVoters(model) + } catch { + self?.presenter?.didReceiveError(.votesFetchFailed(error)) + } + } + } + + let operations = voterWrapper.allOperations + identityWrapper.allOperations + [mappingOperation] + + operationQueue.addOperations(operations, waitUntilFinished: false) + } +} + +extension ReferendumVotersInteractor: ReferendumVotersInteractorInputProtocol { + func setup() { + provideVoters() + } + + func refreshVoters() { + provideVoters() + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift new file mode 100644 index 0000000000..c47e96eeb6 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift @@ -0,0 +1,21 @@ +import Foundation + +final class ReferendumVotersPresenter { + weak var view: ReferendumVotersViewProtocol? + let wireframe: ReferendumVotersWireframeProtocol + let interactor: ReferendumVotersInteractorInputProtocol + + init( + interactor: ReferendumVotersInteractorInputProtocol, + wireframe: ReferendumVotersWireframeProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + } +} + +extension ReferendumVotersPresenter: ReferendumVotersPresenterProtocol { + func setup() {} +} + +extension ReferendumVotersPresenter: ReferendumVotersInteractorOutputProtocol {} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift new file mode 100644 index 0000000000..2c23a01822 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift @@ -0,0 +1,17 @@ +protocol ReferendumVotersViewProtocol: AnyObject {} + +protocol ReferendumVotersPresenterProtocol: AnyObject { + func setup() +} + +protocol ReferendumVotersInteractorInputProtocol: AnyObject { + func setup() + func refreshVoters() +} + +protocol ReferendumVotersInteractorOutputProtocol: AnyObject { + func didReceiveVoters(_ voters: ReferendumVotersModel) + func didReceiveError(_ error: ReferendumsInteractorError) +} + +protocol ReferendumVotersWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift new file mode 100644 index 0000000000..9f42d12ca6 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift @@ -0,0 +1,29 @@ +import UIKit + +final class ReferendumVotersViewController: UIViewController { + typealias RootViewType = ReferendumVotersViewLayout + + let presenter: ReferendumVotersPresenterProtocol + + init(presenter: ReferendumVotersPresenterProtocol) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = ReferendumVotersViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + presenter.setup() + } +} + +extension ReferendumVotersViewController: ReferendumVotersViewProtocol {} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift new file mode 100644 index 0000000000..feec690321 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift @@ -0,0 +1,21 @@ +import Foundation + +struct ReferendumVotersViewFactory { + static func createView( + state: GovernanceSharedState, + referendum: ReferendumLocal, + type: ReferendumVotersType + ) -> ReferendumVotersViewProtocol? { + let interactor = ReferendumVotersInteractor() + let wireframe = ReferendumVotersWireframe() + + let presenter = ReferendumVotersPresenter(interactor: interactor, wireframe: wireframe) + + let view = ReferendumVotersViewController(presenter: presenter) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift new file mode 100644 index 0000000000..5f20d8187c --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift @@ -0,0 +1,13 @@ +import UIKit + +final class ReferendumVotersViewLayout: UIView { + + override init(frame: CGRect) { + super.init(frame: frame) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersWireframe.swift new file mode 100644 index 0000000000..81de1750db --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class ReferendumVotersWireframe: ReferendumVotersWireframeProtocol {} \ No newline at end of file From 0483f315f116b61148111a744cd954a0cf937dcf Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 15 Oct 2022 10:37:55 +0500 Subject: [PATCH 046/229] add voters screen --- novawallet.xcodeproj/project.pbxproj | 28 +++++ .../ReferendumVotersInteractor.swift | 4 +- .../ReferendumVotersPresenter.swift | 116 +++++++++++++++++- .../ReferendumVotersProtocols.swift | 10 +- .../ReferendumVotersViewController.swift | 96 ++++++++++++++- .../ReferendumVotersViewFactory.swift | 75 ++++++++++- .../ReferendumVotersViewLayout.swift | 23 +++- .../ReferendumVotersWireframe.swift | 2 +- .../View/ReferendumVotersTableViewCell.swift | 84 +++++++++++++ .../ViewModel/ReferendumVotersViewModel.swift | 17 +++ .../ReferendumDisplayStringFactory.swift | 70 +++++++++++ novawallet/en.lproj/Localizable.strings | 4 + novawallet/ru.lproj/Localizable.strings | 4 + 13 files changed, 517 insertions(+), 16 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoters/ViewModel/ReferendumVotersViewModel.swift create mode 100644 novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 9fbbe574a1..3740da7486 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1219,6 +1219,9 @@ 8483B15128F93A080048B295 /* ReferendumVotersType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15028F93A080048B295 /* ReferendumVotersType.swift */; }; 8483B15328F940080048B295 /* ReferendumVotersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15228F940080048B295 /* ReferendumVotersModel.swift */; }; 8483B15528F9406C0048B295 /* ReferendumVotersInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15428F9406C0048B295 /* ReferendumVotersInteractorError.swift */; }; + 8483B15828F98C9F0048B295 /* ReferendumVotersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15728F98C9F0048B295 /* ReferendumVotersViewModel.swift */; }; + 8483B15B28F991550048B295 /* ReferendumVotersTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15A28F991550048B295 /* ReferendumVotersTableViewCell.swift */; }; + 8483B15D28FA79620048B295 /* ReferendumDisplayStringFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */; }; 8485D924277E16C400767243 /* DAppBrowserScriptHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */; }; 84873AFF26028E2B000A83EE /* StakingStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */; }; 84873B0426029B75000A83EE /* StakingEstimationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */; }; @@ -4062,6 +4065,9 @@ 8483B15028F93A080048B295 /* ReferendumVotersType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotersType.swift; sourceTree = ""; }; 8483B15228F940080048B295 /* ReferendumVotersModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotersModel.swift; sourceTree = ""; }; 8483B15428F9406C0048B295 /* ReferendumVotersInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotersInteractorError.swift; sourceTree = ""; }; + 8483B15728F98C9F0048B295 /* ReferendumVotersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotersViewModel.swift; sourceTree = ""; }; + 8483B15A28F991550048B295 /* ReferendumVotersTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotersTableViewCell.swift; sourceTree = ""; }; + 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDisplayStringFactory.swift; sourceTree = ""; }; 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserScriptHandler.swift; sourceTree = ""; }; 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingStateMachine.swift; sourceTree = ""; }; 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingEstimationViewModel.swift; sourceTree = ""; }; @@ -6140,6 +6146,8 @@ 357F2FABE25DB08B50B329CF /* ReferendumVoters */ = { isa = PBXGroup; children = ( + 8483B15928F991400048B295 /* View */, + 8483B15628F98C700048B295 /* ViewModel */, 8483B14F28F939F30048B295 /* Model */, E6FE9E98CB265815986BE909 /* ReferendumVotersProtocols.swift */, E9FBF368FBB46AD4DE606DB1 /* ReferendumVotersWireframe.swift */, @@ -7760,6 +7768,7 @@ 88B438E628F6C629001FC08A /* StatusTimeViewModel.swift */, 8455AB4428F7F05400974E88 /* ReferendumStatusViewModelFactory.swift */, 8455AB4928F80D9300974E88 /* ReferendumTrackType.swift */, + 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */, ); path = ViewModel; sourceTree = ""; @@ -8534,6 +8543,22 @@ path = Model; sourceTree = ""; }; + 8483B15628F98C700048B295 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 8483B15728F98C9F0048B295 /* ReferendumVotersViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + 8483B15928F991400048B295 /* View */ = { + isa = PBXGroup; + children = ( + 8483B15A28F991550048B295 /* ReferendumVotersTableViewCell.swift */, + ); + path = View; + sourceTree = ""; + }; 8487582227F06AF300495306 /* QRScanner */ = { isa = PBXGroup; children = ( @@ -15145,6 +15170,7 @@ 848077D22837CAE5003B7C79 /* ParachainStakingErrorPresentable.swift in Sources */, 84F4387025D9BC3900AEDA56 /* EmptyStreamableSource.swift in Sources */, 842A736F27DB7E57006EE1EA /* OperationExtrinsicViewModel.swift in Sources */, + 8483B15D28FA79620048B295 /* ReferendumDisplayStringFactory.swift in Sources */, 8498430326592D29006BBB9F /* VoteStatusSectionView.swift in Sources */, 840D891D26242AE500AB231B /* StorageRequest.swift in Sources */, 8401AEC82642A71D000B03E3 /* StakingRebondConfirmationProtocols.swift in Sources */, @@ -15188,6 +15214,7 @@ 844AE53C2861B3BC0020ECBC /* XcmTransferService.swift in Sources */, 2A9F8D52274E4EC4003720E0 /* AccountCreateViewController.swift in Sources */, 84113B91255B2CA0009BD21A /* MainTransitionHelper.swift in Sources */, + 8483B15B28F991550048B295 /* ReferendumVotersTableViewCell.swift in Sources */, 84B6349D28F4A06D00503306 /* Preimage.swift in Sources */, 8428768524AE046300D91AD8 /* LanguageSelectionProtocols.swift in Sources */, 2A90206E273E6CA200F2D584 /* NetworkFeeConfirmView+Protocol.swift in Sources */, @@ -15864,6 +15891,7 @@ 20B2942A4241F6713A1C70D9 /* StakingRewardDetailsViewFactory.swift in Sources */, 84F13F0A26F14122006725FF /* ChainAsset.swift in Sources */, 848CCB442832EE9B00A1FD00 /* GeneralStorageSubscriptionFactory.swift in Sources */, + 8483B15828F98C9F0048B295 /* ReferendumVotersViewModel.swift in Sources */, 84BB3CEE267CD6B500676FFE /* CrowdloanContributionDict.swift in Sources */, 8473F4B4282BD5A1007CC55A /* StakingRelaychainInteractor.swift in Sources */, 845B821B26EF80BC00D25C72 /* MetaAccountModel.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift index eaabaef4f2..572e7e76b5 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift @@ -41,7 +41,7 @@ final class ReferendumVotersInteractor { let identityWrapper = identityOperationFactory.createIdentityWrapper( for: { let voters = try voterWrapper.targetOperation.extractNoCancellableResultData() - return voters.map { $0.accountId } + return voters.map(\.accountId) }, engine: connection, runtimeService: runtimeProvider, @@ -65,7 +65,7 @@ final class ReferendumVotersInteractor { let model = try mappingOperation.extractNoCancellableResultData() self?.presenter?.didReceiveVoters(model) } catch { - self?.presenter?.didReceiveError(.votesFetchFailed(error)) + self?.presenter?.didReceiveError(.votersFetchFailed(error)) } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift index c47e96eeb6..9a0ce6f172 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift @@ -1,21 +1,131 @@ import Foundation +import SoraFoundation +import BigInt final class ReferendumVotersPresenter { weak var view: ReferendumVotersViewProtocol? let wireframe: ReferendumVotersWireframeProtocol let interactor: ReferendumVotersInteractorInputProtocol + let stringFactory: ReferendumDisplayStringFactoryProtocol + + let referendum: ReferendumLocal + let chain: ChainModel + let type: ReferendumVotersType + let logger: LoggerProtocol + + private var model: ReferendumVotersModel? + + private lazy var displayAddressFactory = DisplayAddressViewModelFactory() init( interactor: ReferendumVotersInteractorInputProtocol, - wireframe: ReferendumVotersWireframeProtocol + wireframe: ReferendumVotersWireframeProtocol, + type: ReferendumVotersType, + referendum: ReferendumLocal, + chain: ChainModel, + stringFactory: ReferendumDisplayStringFactoryProtocol, + localizationManager: LocalizationManagerProtocol, + logger: LoggerProtocol ) { self.interactor = interactor self.wireframe = wireframe + self.type = type + self.referendum = referendum + self.stringFactory = stringFactory + self.chain = chain + self.logger = logger + + self.localizationManager = localizationManager + } + + private func updateView() { + guard let model = model else { + return + } + + let viewModels: [ReferendumVotersViewModel] = model.voters.filter { voter in + switch type { + case .ayes: + return voter.vote.ayes > 0 + case .nays: + return voter.vote.nays > 0 + } + }.compactMap { voter in + guard let address = try? voter.accountId.toAddress(using: chain.chainFormat) else { + return nil + } + + let displayAddressViewModel: DisplayAddressViewModel + + if let displayName = model.identites[address]?.displayName { + let displayAddress = DisplayAddress(address: address, username: displayName) + displayAddressViewModel = displayAddressFactory.createViewModel(from: displayAddress) + } else { + displayAddressViewModel = displayAddressFactory.createViewModel(from: address) + } + + let amountInPlank: BigUInt + let votes: BigUInt + + switch type { + case .ayes: + amountInPlank = voter.vote.ayeBalance + votes = voter.vote.ayes + case .nays: + amountInPlank = voter.vote.nayBalance + votes = voter.vote.nays + } + + let votesString = stringFactory.createVotes(from: votes, chain: chain, locale: selectedLocale) + let details = stringFactory.createVotesDetails( + from: amountInPlank, + conviction: voter.vote.conviction, + chain: chain, + locale: selectedLocale + ) + + return ReferendumVotersViewModel( + displayAddress: displayAddressViewModel, + votes: votesString ?? "", + preConviction: details ?? "" + ) + } + + view?.didReceiveViewModels(.loaded(value: viewModels)) } } extension ReferendumVotersPresenter: ReferendumVotersPresenterProtocol { - func setup() {} + func setup() { + view?.didReceiveViewModels(.loading) + + interactor.setup() + } + + func selectVoter(at _: Int) {} } -extension ReferendumVotersPresenter: ReferendumVotersInteractorOutputProtocol {} \ No newline at end of file +extension ReferendumVotersPresenter: ReferendumVotersInteractorOutputProtocol { + func didReceiveVoters(_ voters: ReferendumVotersModel) { + model = voters + + updateView() + } + + func didReceiveError(_ error: ReferendumVotersInteractorError) { + logger.error("Did receive error: \(error)") + + switch error { + case .votersFetchFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.updateView() + } + } + } +} + +extension ReferendumVotersPresenter: Localizable { + func applyLocalization() { + updateView() + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift index 2c23a01822..01a5ee09c3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift @@ -1,7 +1,11 @@ -protocol ReferendumVotersViewProtocol: AnyObject {} +protocol ReferendumVotersViewProtocol: ControllerBackedProtocol { + func didReceiveViewModels(_ viewModels: LoadableViewModelState<[ReferendumVotersViewModel]>) +} protocol ReferendumVotersPresenterProtocol: AnyObject { func setup() + + func selectVoter(at index: Int) } protocol ReferendumVotersInteractorInputProtocol: AnyObject { @@ -11,7 +15,7 @@ protocol ReferendumVotersInteractorInputProtocol: AnyObject { protocol ReferendumVotersInteractorOutputProtocol: AnyObject { func didReceiveVoters(_ voters: ReferendumVotersModel) - func didReceiveError(_ error: ReferendumsInteractorError) + func didReceiveError(_ error: ReferendumVotersInteractorError) } -protocol ReferendumVotersWireframeProtocol: AnyObject {} +protocol ReferendumVotersWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift index 9f42d12ca6..969a95638b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift @@ -1,13 +1,29 @@ import UIKit +import SoraFoundation -final class ReferendumVotersViewController: UIViewController { +final class ReferendumVotersViewController: UIViewController, ViewHolder { typealias RootViewType = ReferendumVotersViewLayout + typealias DataSource = UITableViewDiffableDataSource + + private var dataSource: DataSource? + private let votersType: ReferendumVotersType + private let quantityFormatter: LocalizableResource let presenter: ReferendumVotersPresenterProtocol - init(presenter: ReferendumVotersPresenterProtocol) { + init( + presenter: ReferendumVotersPresenterProtocol, + votersType: ReferendumVotersType, + quantityFormatter: LocalizableResource, + localizationManager: LocalizationManagerProtocol + ) { self.presenter = presenter + self.votersType = votersType + self.quantityFormatter = quantityFormatter + super.init(nibName: nil, bundle: nil) + + self.localizationManager = localizationManager } @available(*, unavailable) @@ -22,8 +38,82 @@ final class ReferendumVotersViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + setupLocalization() + configureTableView() + presenter.setup() } + + private func configureTableView() { + rootView.tableView.registerClassForCell(ReferendumVotersTableViewCell.self) + rootView.tableView.delegate = self + + dataSource = DataSource( + tableView: rootView.tableView + ) { tableView, _, viewModel in + let cell = tableView.dequeueReusableCellWithType(ReferendumVotersTableViewCell.self) + cell?.bind(viewModel: viewModel) + return cell + } + } + + private func setupLocalization() { + switch votersType { + case .ayes: + title = R.string.localizable.govVotersAye(preferredLanguages: selectedLocale.rLanguages) + case .nays: + title = R.string.localizable.govVotersNay(preferredLanguages: selectedLocale.rLanguages) + } + } + + private func setupCounter(value: Int?) { + navigationItem.rightBarButtonItem = nil + + let formatter = quantityFormatter.value(for: selectedLocale) + + guard + let value = value, + let valueString = formatter.string(from: value as NSNumber) else { + return + } + + rootView.totalVotersLabel.titleLabel.text = valueString + rootView.totalVotersLabel.sizeToFit() + + navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rootView.totalVotersLabel) + } } -extension ReferendumVotersViewController: ReferendumVotersViewProtocol {} \ No newline at end of file +extension ReferendumVotersViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + presenter.selectVoter(at: indexPath.row) + } +} + +extension ReferendumVotersViewController: ReferendumVotersViewProtocol { + func didReceiveViewModels(_ viewModels: LoadableViewModelState<[ReferendumVotersViewModel]>) { + var snapshot = NSDiffableDataSourceSnapshot() + + switch viewModels { + case let .loaded(value), let .cached(value): + snapshot.reloadItems(value) + + setupCounter(value: value.count) + case .loading: + snapshot.reloadItems([]) + setupCounter(value: nil) + } + + dataSource?.apply(snapshot, animatingDifferences: true) + } +} + +extension ReferendumVotersViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + setupLocalization() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift index feec690321..ab075f0b66 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift @@ -1,4 +1,7 @@ import Foundation +import SubstrateSdk +import RobinHood +import SoraFoundation struct ReferendumVotersViewFactory { static func createView( @@ -6,16 +9,82 @@ struct ReferendumVotersViewFactory { referendum: ReferendumLocal, type: ReferendumVotersType ) -> ReferendumVotersViewProtocol? { - let interactor = ReferendumVotersInteractor() + guard + let interactor = createInteractor(for: state, referendum: referendum), + let chain = state.settings.value + else { + return nil + } + let wireframe = ReferendumVotersWireframe() - let presenter = ReferendumVotersPresenter(interactor: interactor, wireframe: wireframe) + let localizationManager = LocalizationManager.shared + + let stringViewModelFactory = ReferendumDisplayStringFactory( + formatterFactory: AssetBalanceFormatterFactory() + ) + + let presenter = ReferendumVotersPresenter( + interactor: interactor, + wireframe: wireframe, + type: type, + referendum: referendum, + chain: chain, + stringFactory: stringViewModelFactory, + localizationManager: localizationManager, + logger: Logger.shared + ) - let view = ReferendumVotersViewController(presenter: presenter) + let view = ReferendumVotersViewController( + presenter: presenter, + votersType: type, + quantityFormatter: NumberFormatter.quantity.localizableResource(), + localizationManager: localizationManager + ) presenter.view = view interactor.presenter = presenter return view } + + private static func createInteractor( + for state: GovernanceSharedState, + referendum: ReferendumLocal + ) -> ReferendumVotersInteractor? { + guard let chain = state.settings.value else { + return nil + } + + let chainRegistry = ChainRegistryFacade.sharedRegistry + + guard + let connection = chainRegistry.getConnection(for: chain.chainId), + let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + return nil + } + + let operationQueue = OperationQueue() + + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + let referendumsOperationFactory = Gov2OperationFactory(requestFactory: requestFactory) + let identityOperationFactory = IdentityOperationFactory( + requestFactory: requestFactory, + emptyIdentitiesWhenNoStorage: true + ) + + return ReferendumVotersInteractor( + referendumIndex: Referenda.ReferendumIndex(referendum.index), + chain: chain, + referendumsOperationFactory: referendumsOperationFactory, + identityOperationFactory: identityOperationFactory, + connection: connection, + runtimeProvider: runtimeProvider, + operationQueue: operationQueue + ) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift index 5f20d8187c..d073e8da68 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift @@ -1,13 +1,34 @@ import UIKit final class ReferendumVotersViewLayout: UIView { + let totalVotersLabel: BorderedLabelView = .create { view in + view.backgroundView.fillColor = R.color.colorWhite16()! + view.titleLabel.apply(style: .init(textColor: R.color.colorWhite80()!, font: .semiBoldFootnote)) + } + + let tableView: UITableView = .create { view in + view.separatorStyle = .none + } override init(frame: CGRect) { super.init(frame: frame) + + backgroundColor = R.color.colorBlack()! + + setupLayout() } @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } -} \ No newline at end of file + + private func setupLayout() { + addSubview(tableView) + + tableView.snp.makeConstraints { make in + make.top.equalTo(safeAreaLayoutGuide) + make.leading.trailing.bottom.equalToSuperview() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersWireframe.swift index 81de1750db..f962cf284a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersWireframe.swift @@ -1,3 +1,3 @@ import Foundation -final class ReferendumVotersWireframe: ReferendumVotersWireframeProtocol {} \ No newline at end of file +final class ReferendumVotersWireframe: ReferendumVotersWireframeProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift new file mode 100644 index 0000000000..f6c3e8e877 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift @@ -0,0 +1,84 @@ +import UIKit + +final class ReferendumVotersTableViewCell: UITableViewCell { + typealias ContentView = GenericTitleValueView, MultiValueView> + + let baseView = ContentView() + + var iconView: UIImageView { + baseView.titleView.imageView + } + + var nameLabel: UILabel { + baseView.titleView.detailsView.detailsLabel + } + + var indicatorView: UIImageView { + baseView.titleView.detailsView.imageView + } + + var votesLabel: UILabel { + baseView.valueView.valueTop + } + + var detailsLabel: UILabel { + baseView.valueView.valueBottom + } + + private var iconViewModel: ImageViewModelProtocol? + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + setupLayout() + applyStyle() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func bind(viewModel: ReferendumVotersViewModel) { + iconViewModel?.cancel(on: iconView) + iconViewModel = viewModel.displayAddress.imageViewModel + + let imageSize = CGSize(width: baseView.titleView.iconWidth, height: baseView.titleView.iconWidth) + iconViewModel?.loadImage(on: iconView, targetSize: imageSize, animated: true) + + let cellViewModel = viewModel.displayAddress.cellViewModel + nameLabel.text = cellViewModel.details + nameLabel.lineBreakMode = viewModel.displayAddress.lineBreakMode + + votesLabel.text = viewModel.votes + detailsLabel.text = viewModel.preConviction + } + + private func applyStyle() { + baseView.titleView.mode = .iconDetails + baseView.titleView.iconWidth = 24.0 + baseView.titleView.spacing = 12.0 + + baseView.titleView.detailsView.spacing = 4.0 + baseView.titleView.detailsView.iconWidth = 16.0 + + nameLabel.apply(style: UILabel.Style(textColor: R.color.colorWhite()!, font: .regularFootnote)) + indicatorView.image = R.image.iconInfoFilled()?.tinted(with: R.color.colorWhite48()!) + + votesLabel.apply(style: UILabel.Style(textColor: R.color.colorWhite()!, font: .regularFootnote)) + detailsLabel.apply(style: UILabel.Style(textColor: R.color.colorTransparentText()!, font: .caption1)) + + let selectedBackgroundView = UIView() + selectedBackgroundView.backgroundColor = R.color.colorAccentSelected() + self.selectedBackgroundView = selectedBackgroundView + } + + private func setupLayout() { + contentView.addSubview(baseView) + + baseView.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(UIConstants.horizontalInset) + make.top.bottom.equalToSuperview() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ViewModel/ReferendumVotersViewModel.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ViewModel/ReferendumVotersViewModel.swift new file mode 100644 index 0000000000..b650ca5d1c --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ViewModel/ReferendumVotersViewModel.swift @@ -0,0 +1,17 @@ +import Foundation + +struct ReferendumVotersViewModel { + let displayAddress: DisplayAddressViewModel + let votes: String + let preConviction: String +} + +extension ReferendumVotersViewModel: Hashable { + static func == (lhs: ReferendumVotersViewModel, rhs: ReferendumVotersViewModel) -> Bool { + lhs.displayAddress.address == rhs.displayAddress.address + } + + func hash(into hasher: inout Hasher) { + hasher.combine(displayAddress.address) + } +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift new file mode 100644 index 0000000000..3e199e36a4 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift @@ -0,0 +1,70 @@ +import Foundation +import BigInt + +protocol ReferendumDisplayStringFactoryProtocol { + func createVotes(from votes: BigUInt, chain: ChainModel, locale: Locale) -> String? + + func createVotesDetails( + from amount: BigUInt, + conviction: Decimal?, + chain: ChainModel, + locale: Locale + ) -> String? +} + +final class ReferendumDisplayStringFactory: ReferendumDisplayStringFactoryProtocol { + let formatterFactory: AssetBalanceFormatterFactoryProtocol + + init(formatterFactory: AssetBalanceFormatterFactoryProtocol) { + self.formatterFactory = formatterFactory + } + + func createVotes(from votes: BigUInt, chain: ChainModel, locale: Locale) -> String? { + guard let asset = chain.utilityAsset() else { + return nil + } + + let displayInfo = ChainAsset(chain: chain, asset: asset).assetDisplayInfo + + let votesDecimal = Decimal.fromSubstrateAmount(votes, precision: displayInfo.assetPrecision) ?? 0 + + let displayFormatter = formatterFactory.createDisplayFormatter(for: displayInfo).value(for: locale) + + if let votesValueString = displayFormatter.stringFromDecimal(votesDecimal) { + return R.string.localizable.govCommonVotesFormat(votesValueString, preferredLanguages: locale.rLanguages) + } else { + return nil + } + } + + func createVotesDetails( + from amount: BigUInt, + conviction: Decimal?, + chain: ChainModel, + locale: Locale + ) -> String? { + guard let asset = chain.utilityAsset() else { + return nil + } + + let displayInfo = ChainAsset(chain: chain, asset: asset).assetDisplayInfo + + let displayFormatter = formatterFactory.createDisplayFormatter(for: displayInfo).value(for: locale) + let tokenFormatter = formatterFactory.createTokenFormatter(for: displayInfo).value(for: locale) + + let optConvictionString = displayFormatter.stringFromDecimal(conviction ?? 0) + + let amountDecimal = Decimal.fromSubstrateAmount(amount, precision: displayInfo.assetPrecision) ?? 0 + let optAmountString = tokenFormatter.stringFromDecimal(amountDecimal) + + if let convictionString = optConvictionString, let amountString = optAmountString { + return R.string.localizable.govCommonAmountConvictionFormat( + amountString, + convictionString, + preferredLanguages: locale.rLanguages + ) + } else { + return nil + } + } +} diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 714ecdbb0f..48264192d5 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1021,3 +1021,7 @@ "gov.track.big.spender" = "Treasury: Big Spend"; "gov.track.whitelisted.caller" = "Fellowship: Whitelist"; "gov.track.fellowship.admin" = "Fellowship: Admin"; +"gov.voters.aye" = "Aye voters"; +"gov.voters.nay" = "Nay voters"; +"gov.common.votes.format" = "%@ votes"; +"gov.common.amount.conviction.format" = "%@ × %@x"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 382af2c298..b9a1e37cb4 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1022,3 +1022,7 @@ "gov.track.big.spender" = "Treasury: Big Spend"; "gov.track.whitelisted.caller" = "Fellowship: Whitelist"; "gov.track.fellowship.admin" = "Fellowship: Admin"; +"gov.voters.aye" = "За голосовали"; +"gov.voters.nay" = "Против голосовали"; +"gov.common.votes.format" = "%@ голосов"; +"gov.common.amount.conviction.format" = "%@ × %@x"; From c7b5d9896f17c468a24bc4b2a1409b4e26b4afeb Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 16 Oct 2022 11:29:41 +0500 Subject: [PATCH 047/229] add referendum voters list --- novawallet/Common/View/MultiValueView.swift | 6 +++ .../ReferendumVotersViewController.swift | 45 ++++++++++--------- .../ReferendumVotersViewLayout.swift | 4 ++ .../View/ReferendumVotersTableViewCell.swift | 9 ++++ .../Referendums/ReferendumsPresenter.swift | 10 ++++- .../Referendums/ReferendumsProtocols.swift | 6 ++- .../Referendums/ReferendumsViewManager.swift | 7 +++ .../Referendums/ReferendumsWireframe.swift | 19 ++++++++ .../Parent/VoteChildPresenterFactory.swift | 2 +- 9 files changed, 83 insertions(+), 25 deletions(-) diff --git a/novawallet/Common/View/MultiValueView.swift b/novawallet/Common/View/MultiValueView.swift index c1043e7fe8..53e81cef15 100644 --- a/novawallet/Common/View/MultiValueView.swift +++ b/novawallet/Common/View/MultiValueView.swift @@ -15,6 +15,12 @@ class MultiValueView: GenericMultiValueView { fatalError("init(coder:) has not been implemented") } + override var intrinsicContentSize: CGSize { + var size = super.intrinsicContentSize + size.width = max(valueTop.intrinsicContentSize.width, valueBottom.intrinsicContentSize.width) + return size + } + func bind(topValue: String, bottomValue: String?) { valueTop.text = topValue diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift index 969a95638b..af887c7991 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift @@ -3,12 +3,12 @@ import SoraFoundation final class ReferendumVotersViewController: UIViewController, ViewHolder { typealias RootViewType = ReferendumVotersViewLayout - typealias DataSource = UITableViewDiffableDataSource - private var dataSource: DataSource? private let votersType: ReferendumVotersType private let quantityFormatter: LocalizableResource + private var state: LoadableViewModelState<[ReferendumVotersViewModel]>? + let presenter: ReferendumVotersPresenterProtocol init( @@ -47,14 +47,8 @@ final class ReferendumVotersViewController: UIViewController, ViewHolder { private func configureTableView() { rootView.tableView.registerClassForCell(ReferendumVotersTableViewCell.self) rootView.tableView.delegate = self - - dataSource = DataSource( - tableView: rootView.tableView - ) { tableView, _, viewModel in - let cell = tableView.dequeueReusableCellWithType(ReferendumVotersTableViewCell.self) - cell?.bind(viewModel: viewModel) - return cell - } + rootView.tableView.dataSource = self + rootView.tableView.rowHeight = 44.0 } private func setupLocalization() { @@ -84,6 +78,22 @@ final class ReferendumVotersViewController: UIViewController, ViewHolder { } } +extension ReferendumVotersViewController: UITableViewDataSource { + func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + state?.value?.count ?? 0 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCellWithType(ReferendumVotersTableViewCell.self)! + + if let viewModel = state?.value?[indexPath.row] { + cell.bind(viewModel: viewModel) + } + + return cell + } +} + extension ReferendumVotersViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) @@ -94,19 +104,10 @@ extension ReferendumVotersViewController: UITableViewDelegate { extension ReferendumVotersViewController: ReferendumVotersViewProtocol { func didReceiveViewModels(_ viewModels: LoadableViewModelState<[ReferendumVotersViewModel]>) { - var snapshot = NSDiffableDataSourceSnapshot() - - switch viewModels { - case let .loaded(value), let .cached(value): - snapshot.reloadItems(value) - - setupCounter(value: value.count) - case .loading: - snapshot.reloadItems([]) - setupCounter(value: nil) - } + state = viewModels + rootView.tableView.reloadData() - dataSource?.apply(snapshot, animatingDifferences: true) + setupCounter(value: viewModels.value?.count) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift index d073e8da68..fc6bb10e6f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift @@ -4,10 +4,14 @@ final class ReferendumVotersViewLayout: UIView { let totalVotersLabel: BorderedLabelView = .create { view in view.backgroundView.fillColor = R.color.colorWhite16()! view.titleLabel.apply(style: .init(textColor: R.color.colorWhite80()!, font: .semiBoldFootnote)) + view.contentInsets = UIEdgeInsets(top: 2, left: 8, bottom: 2, right: 8) + view.backgroundView.cornerRadius = 6.0 } let tableView: UITableView = .create { view in view.separatorStyle = .none + view.backgroundColor = .clear + view.contentInset = UIEdgeInsets(top: 8.0, left: 0, bottom: 0, right: 0) } override init(frame: CGRect) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift index f6c3e8e877..26d2321998 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift @@ -52,16 +52,25 @@ final class ReferendumVotersTableViewCell: UITableViewCell { votesLabel.text = viewModel.votes detailsLabel.text = viewModel.preConviction + + setNeedsLayout() } private func applyStyle() { + backgroundColor = .clear + + baseView.spacing = 32.0 baseView.titleView.mode = .iconDetails baseView.titleView.iconWidth = 24.0 baseView.titleView.spacing = 12.0 baseView.titleView.detailsView.spacing = 4.0 baseView.titleView.detailsView.iconWidth = 16.0 + baseView.titleView.detailsView.mode = .detailsIcon + + baseView.valueView.stackView.alignment = .fill + nameLabel.numberOfLines = 1 nameLabel.apply(style: UILabel.Style(textColor: R.color.colorWhite()!, font: .regularFootnote)) indicatorView.image = R.image.iconInfoFilled()?.tinted(with: R.color.colorWhite48()!) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index e12b67cec5..f3bfb599f3 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -157,7 +157,15 @@ final class ReferendumsPresenter { } } -extension ReferendumsPresenter: ReferendumsPresenterProtocol {} +extension ReferendumsPresenter: ReferendumsPresenterProtocol { + func select(referendumIndex: UInt) { + guard let referendum = referendums?.first(where: { $0.index == referendumIndex }) else { + return + } + + wireframe.showVoters(from: view, referendum: referendum) + } +} extension ReferendumsPresenter: VoteChildPresenterProtocol { func setup() { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 7de9ed3482..a8c537b110 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -8,7 +8,9 @@ protocol ReferendumsViewProtocol: ControllerBackedProtocol { func updateReferendums(time: [UInt: StatusTimeViewModel?]) } -protocol ReferendumsPresenterProtocol: AnyObject {} +protocol ReferendumsPresenterProtocol: AnyObject { + func select(referendumIndex: UInt) +} protocol ReferendumsInteractorInputProtocol: AnyObject { func setup() @@ -38,4 +40,6 @@ protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, Commo delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId? ) + + func showVoters(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 19f791aefa..078d52394e 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -54,6 +54,13 @@ extension ReferendumsViewManager: UITableViewDataSource { extension ReferendumsViewManager: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) + + let section = model.sections[indexPath.section] + switch section { + case let .active(_, cellModels), let .completed(_, cellModels): + let referendumIndex = cellModels[indexPath.row].referendumIndex + presenter?.select(referendumIndex: referendumIndex) + } } func tableView(_: UITableView, viewForHeaderInSection section: Int) -> UIView? { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index fe82efdb1a..e11e7b19a0 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -1,6 +1,12 @@ import Foundation final class ReferendumsWireframe: ReferendumsWireframeProtocol { + let state: GovernanceSharedState + + init(state: GovernanceSharedState) { + self.state = state + } + func selectChain( from view: ControllerBackedProtocol?, delegate: AssetSelectionDelegate, @@ -24,4 +30,17 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { view?.controller.present(navigationController, animated: true, completion: nil) } + + func showVoters(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) { + guard let votersView = ReferendumVotersViewFactory.createView( + state: state, + referendum: referendum, + type: .ayes + ) else { + return + } + + let navigationController = FearlessNavigationController(rootViewController: votersView.controller) + view?.controller.present(navigationController, animated: true) + } } diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index 6b86a64b80..b12a3c8498 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -173,7 +173,7 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { ) -> VoteChildPresenterProtocol? { let state = GovernanceSharedState() let interactor = createGovernanceInteractor(for: state, wallet: wallet) - let wireframe = ReferendumsWireframe() + let wireframe = ReferendumsWireframe(state: state) let statusViewModelFactory = ReferendumStatusViewModelFactory() From af29048f5976bfe3155345d9ec9980b59fd48f8a Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 16 Oct 2022 14:50:03 +0500 Subject: [PATCH 048/229] add empty state --- .../ReferendumVotersViewController.swift | 51 ++++++++++- .../ReferendumVotersViewLayout.swift | 88 ++++++++++++++++++- .../View/ReferendumVotersTableViewCell.swift | 19 ++-- .../Vote/Parent/View/SkeletonableView.swift | 29 +++++- novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 6 files changed, 176 insertions(+), 13 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift index af887c7991..66d5eb7e12 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift @@ -1,5 +1,6 @@ import UIKit import SoraFoundation +import SoraUI final class ReferendumVotersViewController: UIViewController, ViewHolder { typealias RootViewType = ReferendumVotersViewLayout @@ -44,11 +45,22 @@ final class ReferendumVotersViewController: UIViewController, ViewHolder { presenter.setup() } + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + + switch state { + case .loading: + rootView.updateLoadingState() + case .loaded, .cached, .none: + break + } + } + private func configureTableView() { rootView.tableView.registerClassForCell(ReferendumVotersTableViewCell.self) rootView.tableView.delegate = self rootView.tableView.dataSource = self - rootView.tableView.rowHeight = 44.0 + rootView.tableView.rowHeight = ReferendumVotersTableViewCell.Constants.rowHeight } private func setupLocalization() { @@ -102,12 +114,49 @@ extension ReferendumVotersViewController: UITableViewDelegate { } } +extension ReferendumVotersViewController: EmptyStateViewOwnerProtocol { + var emptyStateDelegate: EmptyStateDelegate { self } + var emptyStateDataSource: EmptyStateDataSource { self } + var contentViewForEmptyState: UIView { rootView } +} + +extension ReferendumVotersViewController: EmptyStateDataSource { + var viewForEmptyState: UIView? { + let emptyView = EmptyStateView() + emptyView.image = R.image.iconSearchHappy()?.tinted(with: R.color.colorWhite()!) + emptyView.title = R.string.localizable.govVotersEmpty(preferredLanguages: selectedLocale.rLanguages) + emptyView.titleColor = R.color.colorWhite()! + emptyView.titleFont = .regularFootnote + return emptyView + } +} + +extension ReferendumVotersViewController: EmptyStateDelegate { + var shouldDisplayEmptyState: Bool { + switch state { + case let .loaded(value), let .cached(value): + return value.isEmpty + case .loading, .none: + return false + } + } +} + extension ReferendumVotersViewController: ReferendumVotersViewProtocol { func didReceiveViewModels(_ viewModels: LoadableViewModelState<[ReferendumVotersViewModel]>) { state = viewModels rootView.tableView.reloadData() setupCounter(value: viewModels.value?.count) + + switch viewModels { + case .loading: + rootView.startLoadingIfNeeded() + case .loaded, .cached: + rootView.stopLoadingIfNeeded() + } + + reloadEmptyState(animated: false) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift index fc6bb10e6f..62422be43a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewLayout.swift @@ -1,17 +1,20 @@ import UIKit +import SoraUI + +final class ReferendumVotersViewLayout: UIView, AdaptiveDesignable { + var skeletonView: SkrullableView? -final class ReferendumVotersViewLayout: UIView { let totalVotersLabel: BorderedLabelView = .create { view in view.backgroundView.fillColor = R.color.colorWhite16()! view.titleLabel.apply(style: .init(textColor: R.color.colorWhite80()!, font: .semiBoldFootnote)) view.contentInsets = UIEdgeInsets(top: 2, left: 8, bottom: 2, right: 8) - view.backgroundView.cornerRadius = 6.0 + view.backgroundView.cornerRadius = 6 } let tableView: UITableView = .create { view in view.separatorStyle = .none view.backgroundColor = .clear - view.contentInset = UIEdgeInsets(top: 8.0, left: 0, bottom: 0, right: 0) + view.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 0, right: 0) } override init(frame: CGRect) { @@ -36,3 +39,82 @@ final class ReferendumVotersViewLayout: UIView { } } } + +extension ReferendumVotersViewLayout: SkeletonableView { + var skeletonSpaceSize: CGSize { + CGSize(width: frame.width, height: ReferendumVotersTableViewCell.Constants.rowHeight) + } + + var skeletonReplica: SkeletonableViewReplica { + let count = UInt32(20 * designScaleRatio.height) + + return SkeletonableViewReplica(count: count, spacing: 0.0) + } + + var hidingViews: [UIView] { [] } + + var skeletonSuperview: UIView { self } + + // swiftlint:disable:next function_body_length + func createSkeletons(for spaceSize: CGSize) -> [Skeletonable] { + let centerY = tableView.contentInset.top + spaceSize.height / 2.0 + let insetX = UIConstants.horizontalInset + + let imageSize = CGSize(width: 22.0, height: 22.0) + + let nameSize = CGSize(width: 120.0, height: 14) + let nameOffsetX = insetX + imageSize.width + ReferendumVotersTableViewCell.Constants.addressNameSpacing + + let indicatorSize = CGSize(width: 12, height: 12) + let indicatorOffsetX = nameOffsetX + nameSize.width + + ReferendumVotersTableViewCell.Constants.addressIndicatorSpacing + + let votesSize = CGSize(width: 60, height: 14) + + let votesDetailsSize = CGSize(width: 80, height: 14) + + return [ + SingleSkeleton.createRow( + on: tableView, + containerView: self, + spaceSize: spaceSize, + offset: CGPoint(x: insetX, y: centerY - imageSize.height / 2.0), + size: imageSize + ), + SingleSkeleton.createRow( + on: tableView, + containerView: self, + spaceSize: spaceSize, + offset: CGPoint(x: nameOffsetX, y: centerY - nameSize.height / 2.0), + size: nameSize + ), + SingleSkeleton.createRow( + on: tableView, + containerView: self, + spaceSize: spaceSize, + offset: CGPoint(x: indicatorOffsetX, y: centerY - indicatorSize.height / 2.0), + size: indicatorSize + ), + SingleSkeleton.createRow( + on: tableView, + containerView: self, + spaceSize: spaceSize, + offset: CGPoint( + x: spaceSize.width - UIConstants.horizontalInset - votesSize.width, + y: tableView.contentInset.top + spaceSize.height / 3 - votesSize.height / 2.0 + ), + size: votesSize + ), + SingleSkeleton.createRow( + on: tableView, + containerView: self, + spaceSize: spaceSize, + offset: CGPoint( + x: spaceSize.width - UIConstants.horizontalInset - votesDetailsSize.width, + y: tableView.contentInset.top + 2 * spaceSize.height / 3 - votesDetailsSize.height / 2.0 + ), + size: votesDetailsSize + ) + ] + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift index 26d2321998..93fe54e3b3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/View/ReferendumVotersTableViewCell.swift @@ -1,6 +1,15 @@ import UIKit final class ReferendumVotersTableViewCell: UITableViewCell { + enum Constants { + static let rowHeight: CGFloat = 44.0 + static let titleValueSpacing: CGFloat = 32.0 + static let addressNameSpacing: CGFloat = 12.0 + static let addressIndicatorSpacing: CGFloat = 4.0 + static let iconSize = CGSize(width: 24.0, height: 24.0) + static let indicatorSize = CGSize(width: 16.0, height: 16.0) + } + typealias ContentView = GenericTitleValueView, MultiValueView> let baseView = ContentView() @@ -59,13 +68,13 @@ final class ReferendumVotersTableViewCell: UITableViewCell { private func applyStyle() { backgroundColor = .clear - baseView.spacing = 32.0 + baseView.spacing = Constants.titleValueSpacing baseView.titleView.mode = .iconDetails - baseView.titleView.iconWidth = 24.0 - baseView.titleView.spacing = 12.0 + baseView.titleView.iconWidth = Constants.iconSize.width + baseView.titleView.spacing = Constants.addressNameSpacing - baseView.titleView.detailsView.spacing = 4.0 - baseView.titleView.detailsView.iconWidth = 16.0 + baseView.titleView.detailsView.spacing = Constants.addressIndicatorSpacing + baseView.titleView.detailsView.iconWidth = Constants.indicatorSize.width baseView.titleView.detailsView.mode = .detailsIcon baseView.valueView.stackView.alignment = .fill diff --git a/novawallet/Modules/Vote/Parent/View/SkeletonableView.swift b/novawallet/Modules/Vote/Parent/View/SkeletonableView.swift index 4a90d537eb..aca3b8cd59 100644 --- a/novawallet/Modules/Vote/Parent/View/SkeletonableView.swift +++ b/novawallet/Modules/Vote/Parent/View/SkeletonableView.swift @@ -1,7 +1,14 @@ import UIKit import SoraUI +struct SkeletonableViewReplica { + let count: UInt32 + let spacing: CGFloat +} + protocol SkeletonableView: UIView { + var skeletonSpaceSize: CGSize { get } + var skeletonReplica: SkeletonableViewReplica { get } var skeletonView: SkrullableView? { get set } var skeletonSuperview: UIView { get } var hidingViews: [UIView] { get } @@ -17,15 +24,18 @@ protocol SkeletonableViewCell { extension SkeletonableView { func startLoadingIfNeeded() { + hidingViews.forEach { $0.alpha = 0 } + guard skeletonView == nil else { return } - hidingViews.forEach { $0.alpha = 0 } setupSkeleton() } func stopLoadingIfNeeded() { + hidingViews.forEach { $0.alpha = 1 } + guard skeletonView != nil else { return } @@ -33,23 +43,34 @@ extension SkeletonableView { skeletonView?.stopSkrulling() skeletonView?.removeFromSuperview() skeletonView = nil + } - hidingViews.forEach { $0.alpha = 1 } + var skeletonSpaceSize: CGSize { frame.size } + + var skeletonReplica: SkeletonableViewReplica { SkeletonableViewReplica(count: 1, spacing: 0) } + + func updateLoadingState() { + setupSkeleton() } private func setupSkeleton() { - let spaceSize = frame.size + let spaceSize = skeletonSpaceSize guard spaceSize.width > 0, spaceSize.height > 0 else { return } - let builder = Skrull( + var builder = Skrull( size: spaceSize, decorations: [], skeletons: createSkeletons(for: spaceSize) ) + let replica = skeletonReplica + if replica.count > 1 { + builder = builder.replicateVertically(count: replica.count, spacing: replica.spacing) + } + let currentSkeletonView: SkrullableView? if let skeletonView = skeletonView { diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 48264192d5..4472662681 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1025,3 +1025,4 @@ "gov.voters.nay" = "Nay voters"; "gov.common.votes.format" = "%@ votes"; "gov.common.amount.conviction.format" = "%@ × %@x"; +"gov.voters.empty" = "When somebody votes for\nthe referendum they will appear here"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index b9a1e37cb4..7c86632967 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1026,3 +1026,4 @@ "gov.voters.nay" = "Против голосовали"; "gov.common.votes.format" = "%@ голосов"; "gov.common.amount.conviction.format" = "%@ × %@x"; +"gov.voters.empty" = "Когда кто-то нибудь проголосует\nза референдум они будут отображаться здесь"; From ae6906077e7df6d6609bfed48d60dddbff9a3f08 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 16 Oct 2022 14:54:59 +0500 Subject: [PATCH 049/229] remove unused code --- .../Referendums/ReferendumsPresenter.swift | 2 -- .../Referendums/ReferendumsProtocols.swift | 2 -- .../Referendums/ReferendumsWireframe.swift | 13 ------------- 3 files changed, 17 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index f3bfb599f3..332af7ebff 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -162,8 +162,6 @@ extension ReferendumsPresenter: ReferendumsPresenterProtocol { guard let referendum = referendums?.first(where: { $0.index == referendumIndex }) else { return } - - wireframe.showVoters(from: view, referendum: referendum) } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index a8c537b110..139ad6279f 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -40,6 +40,4 @@ protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, Commo delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId? ) - - func showVoters(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index e11e7b19a0..75c34588c2 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -30,17 +30,4 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { view?.controller.present(navigationController, animated: true, completion: nil) } - - func showVoters(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) { - guard let votersView = ReferendumVotersViewFactory.createView( - state: state, - referendum: referendum, - type: .ayes - ) else { - return - } - - let navigationController = FearlessNavigationController(rootViewController: votersView.controller) - view?.controller.present(navigationController, animated: true) - } } From de8b177222acddb3bb008e3e8ff04b8cb56253da Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 16 Oct 2022 15:09:35 +0500 Subject: [PATCH 050/229] removed unused code --- .../ViewModel/ReferendumVotersViewModel.swift | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ViewModel/ReferendumVotersViewModel.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ViewModel/ReferendumVotersViewModel.swift index b650ca5d1c..3bfdca02c9 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ViewModel/ReferendumVotersViewModel.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ViewModel/ReferendumVotersViewModel.swift @@ -5,13 +5,3 @@ struct ReferendumVotersViewModel { let votes: String let preConviction: String } - -extension ReferendumVotersViewModel: Hashable { - static func == (lhs: ReferendumVotersViewModel, rhs: ReferendumVotersViewModel) -> Bool { - lhs.displayAddress.address == rhs.displayAddress.address - } - - func hash(into hasher: inout Hasher) { - hasher.combine(displayAddress.address) - } -} From c04732f6ac663d1da1d2d3bd9f3d52e1f50fbcc8 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 17 Oct 2022 07:17:40 +0400 Subject: [PATCH 051/229] added dApp view, added title view --- novawallet.xcodeproj/project.pbxproj | 16 ++- ...pItemView.swift => DAppItemViewCell.swift} | 0 .../ReferendumDetailsViewLayout.swift | 15 +++ .../MyPlayground.playground/Contents.swift | 35 ++++- .../View/ReferendumDAppView.swift | 96 ++++++++++++++ .../View/ReferendumDetailsTitleView.swift | 121 ++++++++++++++++++ .../View/ReferendumTimelineView.swift | 119 +++++++++++++---- .../Governance/View/ReferendumInfoView.swift | 11 +- 8 files changed, 378 insertions(+), 35 deletions(-) rename novawallet/Modules/DApp/DAppList/View/{DAppItemView.swift => DAppItemViewCell.swift} (100%) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 887b08b75c..4d61d3945d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -326,7 +326,7 @@ 8401AEC82642A71D000B03E3 /* StakingRebondConfirmationProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8401AEBF2642A71D000B03E3 /* StakingRebondConfirmationProtocols.swift */; }; 8401F24F24E524900081D8F8 /* String+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8401F24E24E524900081D8F8 /* String+Helpers.swift */; }; 8402CC9C275B92AC00E5BF30 /* ControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8402CC9B275B92AC00E5BF30 /* ControlView.swift */; }; - 8402CC9E275B946100E5BF30 /* DAppItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8402CC9D275B946100E5BF30 /* DAppItemView.swift */; }; + 8402CC9E275B946100E5BF30 /* DAppItemViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8402CC9D275B946100E5BF30 /* DAppItemViewCell.swift */; }; 84031C17263EC95C008FD9D4 /* SetPayeeCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84031C16263EC95C008FD9D4 /* SetPayeeCall.swift */; }; 84038FEC26FFBA4D00C73F3F /* PriceLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84038FEB26FFBA4D00C73F3F /* PriceLocalStorageSubscriber.swift */; }; 84038FEE26FFBA6200C73F3F /* PriceLocalSubscriptionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84038FED26FFBA6200C73F3F /* PriceLocalSubscriptionHandler.swift */; }; @@ -2233,6 +2233,7 @@ 88A6BCFF28CA15400047E4C2 /* LocksBalanceViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A6BCFE28CA15400047E4C2 /* LocksBalanceViewModelFactory.swift */; }; 88A6BD0128CA15710047E4C2 /* LocksViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A6BD0028CA15710047E4C2 /* LocksViewInput.swift */; }; 88A95FA628F8664100BE26F3 /* ReferendumTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A95FA528F8664100BE26F3 /* ReferendumTimelineView.swift */; }; + 88A95FA828FAA99D00BE26F3 /* ReferendumDAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A95FA728FAA99D00BE26F3 /* ReferendumDAppView.swift */; }; 88AA0FB828B60E6A00931800 /* YourWalletsControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AA0FB728B60E6A00931800 /* YourWalletsControlView.swift */; }; 88AC186128CA3EE100892A9B /* LocksViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AC186028CA3EE100892A9B /* LocksViewLayout.swift */; }; 88AC186328CA3F0000892A9B /* GenericCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AC186228CA3F0000892A9B /* GenericCollectionViewLayout.swift */; }; @@ -2259,6 +2260,7 @@ 88F3A9FB9CEA464275F1115E /* ExportMnemonicViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47759907380BE9300E54DC78 /* ExportMnemonicViewFactory.swift */; }; 88F7716028BEA589008C028A /* YourWalletsIconDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7715F28BEA589008C028A /* YourWalletsIconDetailsView.swift */; }; 88F7716428BF6B59008C028A /* GenericMultiValueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7716328BF6B59008C028A /* GenericMultiValueView.swift */; }; + 88FAE78828FCF8E200130B47 /* ReferendumDetailsTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */; }; 8916E9179CF5409E65D1B3A6 /* NftDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A46EE888D60C1538A0A3EFC /* NftDetailsProtocols.swift */; }; 8A19EC93E6A6972327116D80 /* ParaStkStakeConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1139FB38E7D8D25A36726089 /* ParaStkStakeConfirmProtocols.swift */; }; 8A23DD1F4146639EA2F7AEF6 /* LocksViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81B239BD9C150BFE9A82B0 /* LocksViewFactory.swift */; }; @@ -3146,7 +3148,7 @@ 8401AEBF2642A71D000B03E3 /* StakingRebondConfirmationProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StakingRebondConfirmationProtocols.swift; sourceTree = ""; }; 8401F24E24E524900081D8F8 /* String+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Helpers.swift"; sourceTree = ""; }; 8402CC9B275B92AC00E5BF30 /* ControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlView.swift; sourceTree = ""; }; - 8402CC9D275B946100E5BF30 /* DAppItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppItemView.swift; sourceTree = ""; }; + 8402CC9D275B946100E5BF30 /* DAppItemViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppItemViewCell.swift; sourceTree = ""; }; 84031C16263EC95C008FD9D4 /* SetPayeeCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetPayeeCall.swift; sourceTree = ""; }; 84038FEB26FFBA4D00C73F3F /* PriceLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceLocalStorageSubscriber.swift; sourceTree = ""; }; 84038FED26FFBA6200C73F3F /* PriceLocalSubscriptionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceLocalSubscriptionHandler.swift; sourceTree = ""; }; @@ -5073,6 +5075,7 @@ 88A6BCFE28CA15400047E4C2 /* LocksBalanceViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksBalanceViewModelFactory.swift; sourceTree = ""; }; 88A6BD0028CA15710047E4C2 /* LocksViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksViewInput.swift; sourceTree = ""; }; 88A95FA528F8664100BE26F3 /* ReferendumTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumTimelineView.swift; sourceTree = ""; }; + 88A95FA728FAA99D00BE26F3 /* ReferendumDAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDAppView.swift; sourceTree = ""; }; 88AA0FB728B60E6A00931800 /* YourWalletsControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsControlView.swift; sourceTree = ""; }; 88AC186028CA3EE100892A9B /* LocksViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksViewLayout.swift; sourceTree = ""; }; 88AC186228CA3F0000892A9B /* GenericCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericCollectionViewLayout.swift; sourceTree = ""; }; @@ -5099,6 +5102,7 @@ 88F19DDF28D8D0F600F6E459 /* LoadableViewModelState+Addition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoadableViewModelState+Addition.swift"; sourceTree = ""; }; 88F7715F28BEA589008C028A /* YourWalletsIconDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsIconDetailsView.swift; sourceTree = ""; }; 88F7716328BF6B59008C028A /* GenericMultiValueView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericMultiValueView.swift; sourceTree = ""; }; + 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsTitleView.swift; sourceTree = ""; }; 899686C7351A2600FFA08371 /* TransferConfirmOnChainViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TransferConfirmOnChainViewFactory.swift; sourceTree = ""; }; 89CFED2E01AB638656E251AF /* NftListProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftListProtocols.swift; sourceTree = ""; }; 8ADA5C374888879D27DBAA29 /* Pods-novawalletTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-novawalletTests.release.xcconfig"; path = "Target Support Files/Pods-novawalletTests/Pods-novawalletTests.release.xcconfig"; sourceTree = ""; }; @@ -11228,7 +11232,7 @@ children = ( 84EE780327C4CF9E0027357F /* DAppListItemsLoadingView.swift */, 84DA03DA275A31B500E8B326 /* DAppListHeaderView.swift */, - 8402CC9D275B946100E5BF30 /* DAppItemView.swift */, + 8402CC9D275B946100E5BF30 /* DAppItemViewCell.swift */, 8472072F277C335000F593DD /* DAppListFlowLayout.swift */, 84720731277C370600F593DD /* DAppCategoriesView.swift */, 8448D5B5277D717400FAEEBC /* DAppListDecorationView.swift */, @@ -11918,6 +11922,8 @@ 888A3B6628F746D200E15BD2 /* ReferendumVotingStatusDetailsView.swift */, 888A3B6428F73DC300E15BD2 /* ReferendumVotingStatusView.swift */, 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */, + 88A95FA728FAA99D00BE26F3 /* ReferendumDAppView.swift */, + 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */, 88B560BD28F831CC00A5EB59 /* MyPlayground.playground */, ); path = View; @@ -14778,6 +14784,7 @@ 84FA7C1C284F8EB400B648E1 /* PendingExtrinsicInteracting.swift in Sources */, 84BC7043289EEF85008A9758 /* NoSigningSupportWrapper.swift in Sources */, 8460E12925422C5A00826F55 /* WalletCompoundDetailsViewModel.swift in Sources */, + 88A95FA828FAA99D00BE26F3 /* ReferendumDAppView.swift in Sources */, AEA0C8BE2681141700F9666F /* YourValidatorList+SelectedList.swift in Sources */, F466AA90273D188600D14021 /* SettingsRow.swift in Sources */, 8430AAE926022F69005B1066 /* StashState.swift in Sources */, @@ -16050,6 +16057,7 @@ 8487583C27F06AF300495306 /* QRCaptureService.swift in Sources */, 7D707DDD180999C63FD0C4ED /* AssetListViewController.swift in Sources */, 75E689BC8D16786DF2674171 /* AssetListViewLayout.swift in Sources */, + 88FAE78828FCF8E200130B47 /* ReferendumDetailsTitleView.swift in Sources */, 2736BAABAE1389260A0B28D6 /* AssetListViewFactory.swift in Sources */, 88E1E896289C021F00C123A8 /* CurrencyCollectionViewCell.swift in Sources */, BE8CF97B6EA62C75277B78AA /* MoonbeamTermsProtocols.swift in Sources */, @@ -16090,7 +16098,7 @@ A07A987DE3047AF1A786D511 /* DAppListViewLayout.swift in Sources */, 8DF76D04C127E0048B253343 /* DAppListViewFactory.swift in Sources */, 848F8B242864448900204BC4 /* TransferSetupPresenterFactory+OnChain.swift in Sources */, - 8402CC9E275B946100E5BF30 /* DAppItemView.swift in Sources */, + 8402CC9E275B946100E5BF30 /* DAppItemViewCell.swift in Sources */, FFE19A19E5B4ED67A2C61951 /* DAppSearchProtocols.swift in Sources */, F88D85C73094F6A1FC494D87 /* DAppSearchWireframe.swift in Sources */, 84350AD4284580F50031EF24 /* StakingTotalStakePresentable.swift in Sources */, diff --git a/novawallet/Modules/DApp/DAppList/View/DAppItemView.swift b/novawallet/Modules/DApp/DAppList/View/DAppItemViewCell.swift similarity index 100% rename from novawallet/Modules/DApp/DAppList/View/DAppItemView.swift rename to novawallet/Modules/DApp/DAppList/View/DAppItemViewCell.swift diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 7f5675b08e..c3a37fd1e1 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -1,6 +1,14 @@ import UIKit final class ReferendumDetailsViewLayout: UIView { + let containerView: ScrollableContainerView = { + let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) + view.stackView.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) + view.stackView.isLayoutMarginsRelativeArrangement = true + view.stackView.alignment = .fill + return view + }() + override init(frame: CGRect) { super.init(frame: frame) } @@ -9,4 +17,11 @@ final class ReferendumDetailsViewLayout: UIView { required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } + + private func setupLayout() { + addSubview(containerView) + containerView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift index 4db8baec43..43a473282e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift @@ -31,11 +31,11 @@ view.frame = .init( ) var detailsView = ReferendumVotingStatusDetailsView() -view.addSubview(detailsView) -detailsView.snp.makeConstraints { - $0.centerY.equalToSuperview() - $0.leading.trailing.equalToSuperview() -} +// view.addSubview(detailsView) +// detailsView.snp.makeConstraints { +// $0.centerY.equalToSuperview() +// $0.leading.trailing.equalToSuperview() +// } let status = ReferendumVotingStatusView.Model( status: .init(name: "PASSING", kind: .positive), @@ -65,4 +65,29 @@ detailsView.bind(viewModel: .init( buttonText: "Vote" )) +// var statusesView = ReferendumTimelineView() +// view.addSubview(statusesView) +// statusesView.snp.makeConstraints { +// $0.centerY.equalToSuperview() +// $0.leading.trailing.equalToSuperview() +// } +// +// statusesView.bind(viewModel: .init(title: "Timeline", statuses: [ +// .init(title: "Created", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), +// .init(title: "Created", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) +// ])) + +let referendumDAppView = ReferendumDAppView() +view.addSubview(referendumDAppView) +referendumDAppView.snp.makeConstraints { + $0.centerY.equalToSuperview() + $0.leading.trailing.equalToSuperview() +} + +let iconUrl = URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/chains/white/Polkadot.svg")! +referendumDAppView.bind(viewModel: .init( + icon: RemoteImageViewModel(url: iconUrl), + title: "Polkassembly", + subtitle: "Comment and react" +)) PlaygroundPage.current.liveView = view diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift new file mode 100644 index 0000000000..62c0c61589 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift @@ -0,0 +1,96 @@ +import UIKit + +final class ReferendumDAppView: UIView { + let iconImageView: DAppIconView = .create { + $0.contentInsets = Constants.iconInsets + $0.backgroundView.cornerRadius = 12 + $0.backgroundView.strokeWidth = 0.5 + $0.backgroundView.strokeColor = R.color.colorWhite16()! + $0.backgroundView.highlightedStrokeColor = R.color.colorWhite16()! + $0.backgroundView.fillColor = R.color.colorWhite8()! + $0.backgroundView.highlightedFillColor = R.color.colorWhite8()! + } + + let titleView = MultiValueView() + let arrowView = UIImageView(image: R.image.iconChevronRight()) + private var model: Model? + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.hStack( + alignment: .center, + spacing: Constants.horizontalSpace, + [ + iconImageView, + titleView, + UIView(), + arrowView + ] + ) + arrowView.snp.makeConstraints { + $0.size.equalTo(Constants.arrowSize) + } + iconImageView.snp.makeConstraints { + $0.width.height.equalTo(Constants.iconWidth) + } + + titleView.stackView.alignment = .leading + + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalTo(Constants.contentInsets) + } + } +} + +// MARK: - Model + +extension ReferendumDAppView { + struct Model { + let icon: ImageViewModelProtocol? + let title: String + let subtitle: String + } + + func bind(viewModel: Model) { + model?.icon?.cancel(on: iconImageView.imageView) + iconImageView.imageView.image = nil + + model = viewModel + + titleView.valueTop.text = viewModel.title + titleView.valueBottom.text = viewModel.subtitle + + viewModel.icon?.loadImage( + on: iconImageView.imageView, + targetSize: .init(width: Constants.iconWidth, height: Constants.iconWidth), + animated: true + ) + } + + func clear() { + model?.icon?.cancel(on: iconImageView.imageView) + } +} + +// MARK: - Constants + +extension ReferendumDAppView { + enum Constants { + static let arrowSize = CGSize(width: 16, height: 16) + static let horizontalSpace: CGFloat = 12 + static let iconWidth: CGFloat = 48 + static let iconInsets = UIEdgeInsets(top: 6, left: 6, bottom: 6, right: 6) + static let contentInsets = UIEdgeInsets(top: 16, left: 16, bottom: 0, right: 16) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift new file mode 100644 index 0000000000..7804879218 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -0,0 +1,121 @@ +import UIKit + +final class ReferendumDetailsTitleView: UIView { + let trackNameView: BorderedIconLabelView = .create { + $0.iconDetailsView.spacing = 6 + $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) + $0.iconDetailsView.detailsLabel.apply(style: .track) + $0.backgroundView.apply(style: .referendum) + $0.iconDetailsView.detailsLabel.numberOfLines = 1 + } + + let numberLabel: BorderedLabelView = .create { + $0.titleLabel.apply(style: .track) + $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) + $0.backgroundView.apply(style: .referendum) + $0.titleLabel.numberOfLines = 1 + } + + let addressView = PolkadotIconDetailsView() + let infoImageView = UIImageView() + let textView = UITextView() + let moreButton = UIButton() + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.vStack( + spacing: 9, + [ + UIView.hStack( + spacing: 6, + [ + UIView(), + trackNameView, + numberLabel + ]), + UIView.hStack( + spacing: 6, + [ + addressView, + infoImageView, + UIView() + ]), + textView, + moreButton + ] + ) + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } +} + +extension ReferendumDetailsTitleView { + struct Model { + let track: Track? + let accountIcon: DrawableIconViewModel? + let accountName: String + let title: String + let description: String + let buttonText: String + + struct Track { + let titleIcon: TitleIconViewModel + let referendumNumber: String? + } + } + + func bind(viewModel: Model) { + numberLabel.isHidden = viewModel.track?.referendumNumber == nil + trackNameView.iconDetailsView.bind(viewModel: viewModel.track?.titleIcon) + numberLabel.titleLabel.text = viewModel.track?.referendumNumber + + viewModel.accountIcon.map { + addressView.imageView.fillColor = $0.fillColor + addressView.imageView.bind(icon: $0.icon) + } + addressView.titleLabel.text = viewModel.accountName + + let titleAttributedString = NSAttributedString(string: viewModel.title, + attributes: titleAttributes) + let descriptionAttributedString = NSAttributedString(string: viewModel.description, + attributes: descriptionAttributes) + let referndumInfo = NSMutableAttributedString() + referndumInfo.append(titleAttributedString) + referndumInfo.append(descriptionAttributedString) + textView.attributedText = referndumInfo + moreButton.setTitle(viewModel.buttonText, for: .normal) + } + + private var titleAttributes: [NSAttributedString.Key: Any] { + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineBreakMode = .byWordWrapping + return [ + .font: UIFont.boldTitle1, + .foregroundColor: R.color.colorWhite()!, + .paragraphStyle: paragraphStyle + ] + } + + private var descriptionAttributes: [NSAttributedString.Key: Any] { + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineBreakMode = .byWordWrapping + return [ + .font: UIFont.regularSubheadline, + .foregroundColor: R.color.colorWhite64()!, + .paragraphStyle: paragraphStyle + ] + } + +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift index 0e8b0ee669..f83c101f74 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift @@ -1,12 +1,87 @@ import UIKit import SoraUI +final class DotsView: UIView { + var statusesView: [BaselinedView] = [] + + override func draw(_ rect: CGRect) { + super.draw(rect) + + print("createDots") + createDots() + } + + private func createDots() { + let dotX = frame.midX + + guard let context = UIGraphicsGetCurrentContext() else { + return + } + context.setStrokeColor(R.color.colorNovaBlue()!.cgColor) + context.setFillColor(R.color.colorNovaBlue()!.cgColor) + context.setLineWidth(1) + for index in 0 ..< statusesView.count { + let dotY = statusesView[index].firstBaseline.center.y + let firstDot = UIBezierPath( + arcCenter: .init(x: dotX, y: dotY), + radius: 6, + startAngle: 0, + endAngle: 2 * .pi, + clockwise: true + ) + + firstDot.move(to: .init(x: dotX, y: dotY + 6)) + print("x1: \(dotX), y1: \(dotY + 6)") + if index + 1 >= statusesView.count { + return + } + statusesView[index].firstBaseline.layoutIfNeeded() + statusesView[index + 1].firstBaseline.layoutIfNeeded() + + print("1: \(statusesView[index].firstBaseline.frame)") + print("2: \(statusesView[index + 1].firstBaseline.frame)") + + let nextDotY = statusesView[index + 1].firstBaseline.center.y + firstDot.addLine(to: .init(x: dotX, y: nextDotY)) + firstDot.stroke() + firstDot.fill() + + let secondDot = UIBezierPath( + arcCenter: .init(x: dotX, y: nextDotY), + radius: 6, + startAngle: 0, + endAngle: 2 * .pi, + clockwise: true + ) + secondDot.stroke() + secondDot.fill() + print("x2: \(dotX), y2: \(nextDotY)") + } + } + + override var intrinsicContentSize: CGSize { + .init(width: 12, height: UIView.noIntrinsicMetric) + } +} + final class ReferendumTimelineView: UIView { - let dotsView = UIView() + var dotsView = DotsView() private(set) var statusesView: [BaselinedView] = [] + var content = UIStackView() + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } private func setupLayout() { - let content = UIView.hStack( + content = UIView.hStack( [ dotsView, UIView.vStack(statusesView) @@ -19,37 +94,33 @@ final class ReferendumTimelineView: UIView { } } - override func layoutSubviews() { - super.layoutSubviews() - } - private func updateStatuses(model: Model) { + layoutIfNeeded() statusesView = createStatusesView(from: model) - setNeedsLayout() - } - - private func createDots() { - let dotX = dotsView.center.x - - for statusView in statusesView { - let dotY = statusView.firstBaseline.center.y - let path = UIBezierPath( - arcCenter: .init(x: dotX, y: dotY), - radius: 6, - startAngle: 0, - endAngle: 2 * .pi, - clockwise: true - ) + content.arrangedSubviews.forEach { + content.removeArrangedSubview($0) + } + content.addArrangedSubview(dotsView) + content.addArrangedSubview(UIView.vStack(statusesView)) + statusesView.forEach { + $0.snp.makeConstraints { make in + make.height.equalTo(44) + } } + content.setNeedsLayout() + content.layoutIfNeeded() + dotsView.statusesView = statusesView + dotsView.setNeedsDisplay() } private func createStatusesView(from model: Model) -> [BaselinedView] { - model.statuses.map { status in + model.statuses.map { status -> BaselinedView in switch status.subtitle { case let .date(date): let view = MultiValueView() view.valueTop.text = status.title view.valueBottom.text = date + return view case let .interval(model): let view = GenericMultiValueView() view.valueTop.text = status.title @@ -80,6 +151,10 @@ extension ReferendumTimelineView { case interval(TitleIconViewModel) } } + + func bind(viewModel: Model) { + updateStatuses(model: viewModel) + } } protocol BaselinedView: UIView { diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift index d9aee83b6e..ec7bd386fa 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -157,10 +157,13 @@ private extension UILabel.Style { font: .regularSubheadline ) - static let track = UILabel.Style( - textColor: R.color.colorWhite64(), - font: .semiBoldCaps1 - ) +} + +extension UILabel.Style { + static let track = UILabel.Style( + textColor: R.color.colorWhite64(), + font: .semiBoldCaps1 + ) } extension RoundedView.Style { From 7a80db3c728dbe7650f9659c448406d455bf8f45 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Mon, 17 Oct 2022 13:02:44 +0500 Subject: [PATCH 052/229] Update novawallet/ru.lproj/Localizable.strings Co-authored-by: Gulnaz <666lynx666@mail.ru> --- novawallet/ru.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 7c86632967..2ba45caed6 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1026,4 +1026,4 @@ "gov.voters.nay" = "Против голосовали"; "gov.common.votes.format" = "%@ голосов"; "gov.common.amount.conviction.format" = "%@ × %@x"; -"gov.voters.empty" = "Когда кто-то нибудь проголосует\nза референдум они будут отображаться здесь"; +"gov.voters.empty" = "Когда кто-нибудь проголосует\nза референдум они будут отображаться здесь"; From 39d5278a1b7d7f34a900972c558a6e221428d0a9 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 17 Oct 2022 17:51:04 +0500 Subject: [PATCH 053/229] add subscription logic --- novawallet.xcodeproj/project.pbxproj | 64 +++- .../GovMetadataLocalSubscriptionFactory.swift | 2 +- .../Common/Helpers/NotEqualWrapper.swift | 9 + .../Helpers/StorageSubscriptionObserver.swift | 11 + .../CallbackStorageSubscription.swift | 53 +++- .../Model/GovernanceSharedState.swift | 33 +- .../Governance/Model/ReferendumLocal.swift | 4 +- .../Operation/Gov2OperationFactory.swift | 67 ++-- .../GovernanceOperationProtocols.swift | 14 +- .../ReferendumDetailsInteractorError.swift | 1 + .../ReferendumDetailsInteractor.swift | 101 +++--- .../ReferendumDetailsPresenter.swift | 9 +- .../ReferendumDetailsProtocols.swift | 1 + .../ReferendumDetailsViewFactory.swift | 14 +- .../ReferendumVoteSetupInteractor.swift | 7 + .../ReferendumVoteSetupPresenter.swift | 21 ++ .../ReferendumVoteSetupProtocols.swift | 11 + .../ReferendumVoteSetupViewController.swift | 29 ++ .../ReferendumVoteSetupViewFactory.swift | 17 + .../ReferendumVoteSetupViewLayout.swift | 12 + .../ReferendumVoteSetupWireframe.swift | 3 + .../ReferendumVotersInteractor.swift | 4 +- .../ReferendumVotersViewFactory.swift | 2 +- .../Referendums/ReferendumsInteractor.swift | 14 +- .../Referendums/ReferendumsPresenter.swift | 4 +- .../Referendums/ReferendumsProtocols.swift | 2 +- .../Gov2SubscriptionFactory.swift | 299 ++++++++++++++++++ .../GovernanceSubscriptionProtocol.swift | 26 ++ .../ViewModel/ReferendumsModelFactory.swift | 9 +- 29 files changed, 716 insertions(+), 127 deletions(-) create mode 100644 novawallet/Common/Helpers/NotEqualWrapper.swift create mode 100644 novawallet/Common/Helpers/StorageSubscriptionObserver.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift create mode 100644 novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 9426131926..06872f6ecc 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 042799797DF7E6FD02D1D1E6 /* ParitySignerTxScanPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 408CF7752F4F638FA29DFE4A /* ParitySignerTxScanPresenter.swift */; }; 049DA9A36A72CB6F8401769C /* WalletsListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F404EE82BC45BFE0F42E0A4 /* WalletsListWireframe.swift */; }; 04B85867D67D56994D99FF14 /* NftListProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CFED2E01AB638656E251AF /* NftListProtocols.swift */; }; + 04D86D5341406305E60F6D18 /* ReferendumVoteSetupInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024B7E67C0603C53981EC394 /* ReferendumVoteSetupInteractor.swift */; }; 054C4BCDEC29ED5F74A36E8B /* ExportMnemonicPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61EBE466BDCF77E65FDCDF81 /* ExportMnemonicPresenter.swift */; }; 06590486EED4050BADDD32C5 /* AccountManagementPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2B676982F60C55530BDD569 /* AccountManagementPresenter.swift */; }; 0678271BE1BA5BBC084F478A /* RecommendedValidatorListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57C624E71FCE0FFF8EAD5BA9 /* RecommendedValidatorListWireframe.swift */; }; @@ -64,6 +65,7 @@ 1C8D1041448B8FB9DD9BBCF1 /* YourWalletsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62C5AF7E89A8C6CFF5AE03B1 /* YourWalletsProtocols.swift */; }; 1D1DC32EFF13F41677A084B7 /* DAppOperationConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = E675B4C5BE36C0004564105B /* DAppOperationConfirmProtocols.swift */; }; 1EE4FBB79EE6015D7D3EBDC1 /* ParitySignerTxScanWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8B46E3BAB48A2D2E1D2EF4 /* ParitySignerTxScanWireframe.swift */; }; + 1F496969FEE3E160BABDAC66 /* ReferendumVoteSetupProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5159EA2661A6CBE123CCF891 /* ReferendumVoteSetupProtocols.swift */; }; 1F88F3DBFA0BD6D0FDF558F3 /* SelectValidatorsConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 975DECE71DE70DFD866B8E23 /* SelectValidatorsConfirmViewFactory.swift */; }; 20B2942A4241F6713A1C70D9 /* StakingRewardDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2377F8FB07B47637346249F5 /* StakingRewardDetailsViewFactory.swift */; }; 211725E26764530359F53A38 /* ParitySignerTxQrInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7859654B7C1FAC269CA61E71 /* ParitySignerTxQrInteractor.swift */; }; @@ -126,6 +128,7 @@ 2BBD2FAA29C71DC6E0C8A845 /* ParaStkYieldBoostStopPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B15579DAD0DD84AEDA7D01 /* ParaStkYieldBoostStopPresenter.swift */; }; 2C3124A5EBC1AD57C01EEA17 /* SelectValidatorsStartInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEFED3DAA18BCEF0BFA15728 /* SelectValidatorsStartInteractor.swift */; }; 2C9A416905C692DCFA74A0D6 /* DAppListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750C8C7940C944DA4C8CB95F /* DAppListInteractor.swift */; }; + 2CEFF4C2574F0AABE0E9BF89 /* ReferendumVoteSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A058D4A585F253CBF2968D /* ReferendumVoteSetupViewController.swift */; }; 2CF2F93AF862CF54FC46B560 /* PurchaseInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D44421CCD7AD220A05CD0E /* PurchaseInteractor.swift */; }; 2EC610DC06643A00876BED6E /* AssetListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B249C5D43CB86CF62C165F8 /* AssetListWireframe.swift */; }; 2F21134DE157A4B98ED309E2 /* AssetsSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611FBB25D55CF56F36026074 /* AssetsSearchViewController.swift */; }; @@ -303,12 +306,14 @@ 7D707DDD180999C63FD0C4ED /* AssetListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE26599B4E43DC4CE520528 /* AssetListViewController.swift */; }; 7D7D40581C276D60713822E9 /* ParaStkCollatorFiltersPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39503B664F159E5D07FF6281 /* ParaStkCollatorFiltersPresenter.swift */; }; 7E1A03082260E0D31AD394CA /* StakingRewardDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF891BE39D442C2D06DDF3BB /* StakingRewardDetailsProtocols.swift */; }; + 7E2800371BE3B166F3475E90 /* ReferendumVoteSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6CCACED8D5AFA6543845B7 /* ReferendumVoteSetupPresenter.swift */; }; 7E5ACF8DDF17C054E6E1B3D5 /* ParaStkYieldBoostSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C2B3C9875FDA7EE8D168900 /* ParaStkYieldBoostSetupWireframe.swift */; }; 7F5B03517FD0144F7EDE1015 /* YourWalletsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF7A019F89C6CD418AEEE79C /* YourWalletsPresenter.swift */; }; 7FF2D6FEDD352AC51E1DBB3B /* OperationDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D2A26EC9537BD4275A03272 /* OperationDetailsPresenter.swift */; }; 800FCAF66DC8A24020D16A9C /* AccountExportPasswordInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194C9BFEE9BA8C9E448D79AA /* AccountExportPasswordInteractor.swift */; }; 8027EA456C0C13F6DA73D540 /* MoonbeamTermsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 837E9D1F8096A0E9CA0E0CEB /* MoonbeamTermsPresenter.swift */; }; 80E265DD62D96597E4EAA44A /* Pods_novawalletTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D79EAD799CBB1ABB9541A232 /* Pods_novawalletTests.framework */; }; + 811096BAAA6BD237DF2769EA /* ReferendumVoteSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF755EE09598254BB5E59CC2 /* ReferendumVoteSetupViewFactory.swift */; }; 81544BD01F6AD0197588D3C5 /* OperationDetailsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC6917929E4A752B79FE554 /* OperationDetailsWireframe.swift */; }; 821518375113295E41E0481C /* ParitySignerTxQrViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B56BDC7E6221DE292498D3A /* ParitySignerTxQrViewFactory.swift */; }; 8217DCBEB74527D57AC82070 /* ParaStkStakeConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10E27EB6FF31F9D247DEFABB /* ParaStkStakeConfirmViewLayout.swift */; }; @@ -891,6 +896,10 @@ 84532D6128E4234700EF4ADC /* ConvictionVotingForKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84532D6028E4234700EF4ADC /* ConvictionVotingForKey.swift */; }; 845353BB2886E3B4006C871A /* OnboardingMainViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845353BA2886E3B4006C871A /* OnboardingMainViewLayout.swift */; }; 845353BD2886EB1A006C871A /* ButtonLargeControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845353BC2886EB1A006C871A /* ButtonLargeControl.swift */; }; + 8453DE5528FD24FF0055345C /* GovernanceSubscriptionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8453DE5428FD24FF0055345C /* GovernanceSubscriptionProtocol.swift */; }; + 8453DE5728FD27390055345C /* Gov2SubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8453DE5628FD27390055345C /* Gov2SubscriptionFactory.swift */; }; + 8453DE5928FD32780055345C /* NotEqualWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8453DE5828FD32780055345C /* NotEqualWrapper.swift */; }; + 8453DE5B28FD32B50055345C /* StorageSubscriptionObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8453DE5A28FD32B50055345C /* StorageSubscriptionObserver.swift */; }; 8454C21D2632A78900657DAD /* EventRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8454C21C2632A78900657DAD /* EventRecord.swift */; }; 8454C2652632B0EF00657DAD /* EventCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8454C2642632B0EF00657DAD /* EventCodingPath.swift */; }; 8454C26A2632B8CE00657DAD /* BalanceDepositEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8454C2692632B8CE00657DAD /* BalanceDepositEvent.swift */; }; @@ -1029,8 +1038,8 @@ 846952A42852A1640083E0B4 /* StakingDuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846952A32852A1640083E0B4 /* StakingDuration.swift */; }; 846952A62852A1E60083E0B4 /* AuraStakingDurationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846952A52852A1E60083E0B4 /* AuraStakingDurationFactory.swift */; }; 8469936B26CD1BBE002CC786 /* RuntimePoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8469936A26CD1BBE002CC786 /* RuntimePoolTests.swift */; }; - 8469D5A828F683930074FEE3 /* ReferendumDetailsInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8469D5A728F683930074FEE3 /* ReferendumDetailsInteractorError.swift */; }; 8469D5A628F5E8F20074FEE3 /* Staking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8469D5A528F5E8F20074FEE3 /* Staking.swift */; }; + 8469D5A828F683930074FEE3 /* ReferendumDetailsInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8469D5A728F683930074FEE3 /* ReferendumDetailsInteractorError.swift */; }; 846A2601267C768500429A7F /* CrowdloanContributionMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A2600267C768500429A7F /* CrowdloanContributionMapper.swift */; }; 846A2606267C792000429A7F /* CrowdloanContributionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A2605267C792000429A7F /* CrowdloanContributionResponse.swift */; }; 846A2C4325271CDE00731018 /* TransactionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A2C4225271CDE00731018 /* TransactionType.swift */; }; @@ -2542,6 +2551,7 @@ CE2792E78B14CE02394D8CF4 /* ReferralCrowdloanViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 594BC61689EC942ED0A64A4A /* ReferralCrowdloanViewLayout.swift */; }; CE4C1344F03A5132C601A594 /* LocksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D4D2E89D40718677685CE1 /* LocksViewController.swift */; }; CE773CEC15A83AA6D0B404B8 /* DAppListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2BB29AE8E556E6756A4F02 /* DAppListViewController.swift */; }; + D1C4208A89633395AF2FDB74 /* ReferendumVoteSetupViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A3105383F2825940D0105D5 /* ReferendumVoteSetupViewLayout.swift */; }; D1C6EABB48DC3EE254E5A095 /* CrowdloanContributionConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28F5B57A24265C36A5F19B78 /* CrowdloanContributionConfirmPresenter.swift */; }; D344C6DAC1F8BB6152BA8DD0 /* RecommendedValidatorListProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C6573C52692E4A56E35FF9 /* RecommendedValidatorListProtocols.swift */; }; D3B48F82A875E301D749AC0B /* StakingUnbondConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5674162035C7D9F226FA9964 /* StakingUnbondConfirmViewController.swift */; }; @@ -2627,6 +2637,7 @@ F0B74A766BF50518323AB25C /* DAppAuthConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A9D9D13EC9D921A2C8FB6D /* DAppAuthConfirmWireframe.swift */; }; F0C3DB0CEE1975626B0014A8 /* StakingUnbondConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C34D496D0F57E685237B3A7 /* StakingUnbondConfirmInteractor.swift */; }; F17C7FA0DB540A803558D1BB /* AnalyticsRewardDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85211D55E2AF0A697FB3EB84 /* AnalyticsRewardDetailsPresenter.swift */; }; + F1BED07F67119E1BD052952A /* ReferendumVoteSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B2C456A80FA66E6F140814 /* ReferendumVoteSetupWireframe.swift */; }; F20C8D17ABF18B7104E14394 /* StakingAmountInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 312DE7ADA5ABC3214AD3D4AD /* StakingAmountInteractor.swift */; }; F27AAD7BC84793FA63027F8C /* AssetsManageInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA134C6DB56DE1DFBA1B88B4 /* AssetsManageInteractor.swift */; }; F382BF4F8C3C46C7C21DE5C0 /* ParaStkUnstakeConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86DCB6F3977BDE1BDC7BC3F9 /* ParaStkUnstakeConfirmPresenter.swift */; }; @@ -2842,6 +2853,7 @@ 00E1485C7B322E477D445C84 /* ChainAddressDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainAddressDetailsProtocols.swift; sourceTree = ""; }; 0100701AA69652CB91ACBD97 /* AssetListInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetListInteractor.swift; sourceTree = ""; }; 01A9D9D13EC9D921A2C8FB6D /* DAppAuthConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthConfirmWireframe.swift; sourceTree = ""; }; + 024B7E67C0603C53981EC394 /* ReferendumVoteSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupInteractor.swift; sourceTree = ""; }; 02ACCC85B2CCF3D9392CA9B4 /* CrowdloanListProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanListProtocols.swift; sourceTree = ""; }; 02D8F02830944DBAF72D8A41 /* MoonbeamTermsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MoonbeamTermsProtocols.swift; sourceTree = ""; }; 037D3CE23FFD176F4F7DABC0 /* ParaStkStakeConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkStakeConfirmViewFactory.swift; sourceTree = ""; }; @@ -3042,6 +3054,7 @@ 502D42F4A480889BA226CAD3 /* StakingMainPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingMainPresenter.swift; sourceTree = ""; }; 50829CD47D3F60E3067418B4 /* ParaStkYieldBoostStartProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStartProtocols.swift; sourceTree = ""; }; 5147BFCC44EB3938D50EE8D9 /* DAppPhishingPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppPhishingPresenter.swift; sourceTree = ""; }; + 5159EA2661A6CBE123CCF891 /* ReferendumVoteSetupProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupProtocols.swift; sourceTree = ""; }; 518305BB475DE40E94DCBD5D /* DAppPhishingWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppPhishingWireframe.swift; sourceTree = ""; }; 5278A5F4178922A240590334 /* DAppBrowserViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppBrowserViewLayout.swift; sourceTree = ""; }; 52B7577593D1A0789B60FF70 /* NftListViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftListViewLayout.swift; sourceTree = ""; }; @@ -3050,11 +3063,13 @@ 52F8D055D0481469073AA859 /* StakingPayoutConfirmationProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPayoutConfirmationProtocols.swift; sourceTree = ""; }; 53235E51143C6E93303E30FE /* DAppSearchViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppSearchViewController.swift; sourceTree = ""; }; 537CCA1F2667A51731C56C88 /* CreateWatchOnlyProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CreateWatchOnlyProtocols.swift; sourceTree = ""; }; + 53A058D4A585F253CBF2968D /* ReferendumVoteSetupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupViewController.swift; sourceTree = ""; }; 53B5C1C920BFDA8F5C9C89D9 /* ParaStkRedeemInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemInteractor.swift; sourceTree = ""; }; 53BE9DEF100A373868EDD03F /* ParaStkSelectCollatorsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkSelectCollatorsWireframe.swift; sourceTree = ""; }; 53C2612BBF75CF0FBD91764E /* ParaStkCollatorsSearchWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorsSearchWireframe.swift; sourceTree = ""; }; 5467B9B6AEDB33F565D130A1 /* ParaStkUnstakeViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeViewFactory.swift; sourceTree = ""; }; 54FB887490A8B33890B4E0E4 /* ControllerAccountConfirmationPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ControllerAccountConfirmationPresenter.swift; sourceTree = ""; }; + 55B2C456A80FA66E6F140814 /* ReferendumVoteSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupWireframe.swift; sourceTree = ""; }; 55E6B5C44D7F43B5C14901ED /* ParaStkUnstakeConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeConfirmWireframe.swift; sourceTree = ""; }; 560C48D7A83F51F001622D71 /* StakingRedeemInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRedeemInteractor.swift; sourceTree = ""; }; 5674162035C7D9F226FA9964 /* StakingUnbondConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondConfirmViewController.swift; sourceTree = ""; }; @@ -3073,6 +3088,7 @@ 5AD16D5FA4115F2A525BDE4F /* ParaStkRedeemViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemViewController.swift; sourceTree = ""; }; 5B8B0940B2CB25AD9C36206E /* SelectValidatorsConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmViewController.swift; sourceTree = ""; }; 5BCDAB970C17F9798AC79B08 /* DAppTxDetailsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsViewController.swift; sourceTree = ""; }; + 5C6CCACED8D5AFA6543845B7 /* ReferendumVoteSetupPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupPresenter.swift; sourceTree = ""; }; 5C92E3ED704CB0BBAB3A669F /* CrowdloanContributionConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmViewLayout.swift; sourceTree = ""; }; 5C96E41F878ED0A0A6F469D3 /* CrowdloanContributionSetupViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupViewFactory.swift; sourceTree = ""; }; 5CD36AD8C414F8973CDA8A0F /* ParaStkUnstakeConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeConfirmViewLayout.swift; sourceTree = ""; }; @@ -3097,6 +3113,7 @@ 6747B9F68F9E92845122D8D2 /* LedgerInstructionsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerInstructionsViewLayout.swift; sourceTree = ""; }; 677CE34BFAB45122C57095F6 /* DAppBrowserViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppBrowserViewFactory.swift; sourceTree = ""; }; 67CAEB35921A61A8EC131AF8 /* LedgerDiscoverViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerDiscoverViewFactory.swift; sourceTree = ""; }; + 6A3105383F2825940D0105D5 /* ReferendumVoteSetupViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupViewLayout.swift; sourceTree = ""; }; 6A695CA303926DFB5D54E309 /* LedgerAccountConfirmationViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerAccountConfirmationViewLayout.swift; sourceTree = ""; }; 6A825B6368073B06F32D7C8F /* StakingMainViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingMainViewFactory.swift; sourceTree = ""; }; 6AD8B98AB03AAF06AA891695 /* TransferConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TransferConfirmViewLayout.swift; sourceTree = ""; }; @@ -3738,6 +3755,10 @@ 84532D6028E4234700EF4ADC /* ConvictionVotingForKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvictionVotingForKey.swift; sourceTree = ""; }; 845353BA2886E3B4006C871A /* OnboardingMainViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingMainViewLayout.swift; sourceTree = ""; }; 845353BC2886EB1A006C871A /* ButtonLargeControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonLargeControl.swift; sourceTree = ""; }; + 8453DE5428FD24FF0055345C /* GovernanceSubscriptionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceSubscriptionProtocol.swift; sourceTree = ""; }; + 8453DE5628FD27390055345C /* Gov2SubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2SubscriptionFactory.swift; sourceTree = ""; }; + 8453DE5828FD32780055345C /* NotEqualWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotEqualWrapper.swift; sourceTree = ""; }; + 8453DE5A28FD32B50055345C /* StorageSubscriptionObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageSubscriptionObserver.swift; sourceTree = ""; }; 8454C21C2632A78900657DAD /* EventRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventRecord.swift; sourceTree = ""; }; 8454C2642632B0EF00657DAD /* EventCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventCodingPath.swift; sourceTree = ""; }; 8454C2692632B8CE00657DAD /* BalanceDepositEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceDepositEvent.swift; sourceTree = ""; }; @@ -3876,8 +3897,8 @@ 846952A32852A1640083E0B4 /* StakingDuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingDuration.swift; sourceTree = ""; }; 846952A52852A1E60083E0B4 /* AuraStakingDurationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuraStakingDurationFactory.swift; sourceTree = ""; }; 8469936A26CD1BBE002CC786 /* RuntimePoolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimePoolTests.swift; sourceTree = ""; }; - 8469D5A728F683930074FEE3 /* ReferendumDetailsInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsInteractorError.swift; sourceTree = ""; }; 8469D5A528F5E8F20074FEE3 /* Staking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Staking.swift; sourceTree = ""; }; + 8469D5A728F683930074FEE3 /* ReferendumDetailsInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsInteractorError.swift; sourceTree = ""; }; 846A2600267C768500429A7F /* CrowdloanContributionMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionMapper.swift; sourceTree = ""; }; 846A2605267C792000429A7F /* CrowdloanContributionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionResponse.swift; sourceTree = ""; }; 846A2C4225271CDE00731018 /* TransactionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionType.swift; sourceTree = ""; }; @@ -5669,6 +5690,7 @@ FE0641B2354E6F236CB9A132 /* NftDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftDetailsPresenter.swift; sourceTree = ""; }; FE4AF0849E32E5B9C72E2ABB /* RecommendedValidatorListViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RecommendedValidatorListViewFactory.swift; sourceTree = ""; }; FF4688AF0658F8BB7A90C2BE /* ExportMnemonicConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ExportMnemonicConfirmViewFactory.swift; sourceTree = ""; }; + FF755EE09598254BB5E59CC2 /* ReferendumVoteSetupViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupViewFactory.swift; sourceTree = ""; }; FFB4A14C99D151B41F61F474 /* DAppTxDetailsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsInteractor.swift; sourceTree = ""; }; FFEBC03AB1841681427D38AF /* StakingRewardPayoutsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardPayoutsViewController.swift; sourceTree = ""; }; FFF3E2C8682E9BCCB0A6872D /* AccountConfirmViewController.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; path = AccountConfirmViewController.xib; sourceTree = ""; }; @@ -7763,6 +7785,15 @@ path = ViewModel; sourceTree = ""; }; + 8453DE5328FD24210055345C /* Subscription */ = { + isa = PBXGroup; + children = ( + 8453DE5428FD24FF0055345C /* GovernanceSubscriptionProtocol.swift */, + 8453DE5628FD27390055345C /* Gov2SubscriptionFactory.swift */, + ); + path = Subscription; + sourceTree = ""; + }; 8455AB4628F7F07200974E88 /* ViewModel */ = { isa = PBXGroup; children = ( @@ -8455,6 +8486,7 @@ 847A25C028D84A3D006AC9F5 /* Governance */ = { isa = PBXGroup; children = ( + 8453DE5328FD24210055345C /* Subscription */, 8455AB4628F7F07200974E88 /* ViewModel */, 880059D628EEA55500E87B9B /* View */, 84A1742528ED60610096F943 /* Operation */, @@ -8463,6 +8495,7 @@ B4F0332763AFF64A3793C679 /* ReferendumDetails */, 872D923BC3CE0F69157DB2EA /* ReferendumFullDetails */, 357F2FABE25DB08B50B329CF /* ReferendumVoters */, + CEE6BB9D4D5A0E46E857EED4 /* ReferendumVoteSetup */, ); path = Governance; sourceTree = ""; @@ -9230,6 +9263,8 @@ 849FA21528A26CB500F83EAA /* CountdownTimerMediator.swift */, 84466B3228B65B5B00FA1E0D /* MetaAccountModel+Identicon.swift */, 847A25BE28D7C2A2006AC9F5 /* AccountIdCodingWrapper.swift */, + 8453DE5828FD32780055345C /* NotEqualWrapper.swift */, + 8453DE5A28FD32B50055345C /* StorageSubscriptionObserver.swift */, ); path = Helpers; sourceTree = ""; @@ -12855,6 +12890,20 @@ path = NftList; sourceTree = ""; }; + CEE6BB9D4D5A0E46E857EED4 /* ReferendumVoteSetup */ = { + isa = PBXGroup; + children = ( + 5159EA2661A6CBE123CCF891 /* ReferendumVoteSetupProtocols.swift */, + 55B2C456A80FA66E6F140814 /* ReferendumVoteSetupWireframe.swift */, + 5C6CCACED8D5AFA6543845B7 /* ReferendumVoteSetupPresenter.swift */, + 024B7E67C0603C53981EC394 /* ReferendumVoteSetupInteractor.swift */, + 53A058D4A585F253CBF2968D /* ReferendumVoteSetupViewController.swift */, + 6A3105383F2825940D0105D5 /* ReferendumVoteSetupViewLayout.swift */, + FF755EE09598254BB5E59CC2 /* ReferendumVoteSetupViewFactory.swift */, + ); + path = ReferendumVoteSetup; + sourceTree = ""; + }; D3537A6D35CC43956A18325B /* ParaStkSelectCollators */ = { isa = PBXGroup; children = ( @@ -15778,6 +15827,7 @@ 848F8B1F2863BB4000204BC4 /* TransferSetupPresenterFactory.swift in Sources */, 3CA86739CB09801714B194BD /* PurchaseWireframe.swift in Sources */, 84FB298C2639ABA500BE0FCD /* YourValidatorList.swift in Sources */, + 8453DE5B28FD32B50055345C /* StorageSubscriptionObserver.swift in Sources */, F4D6FF0E26B3DD6E002313AF /* AnalyticsRewardsProtocols.swift in Sources */, 84873AFF26028E2B000A83EE /* StakingStateMachine.swift in Sources */, 8442002528E6FEEE00C49C4A /* ReferendumsProtocols.swift in Sources */, @@ -15957,6 +16007,7 @@ 841E2E5027381B2A00F250C1 /* AccountInfoSubscriptionHandlingFactory.swift in Sources */, 88AC186128CA3EE100892A9B /* LocksViewLayout.swift in Sources */, 8468119428E6234B00BF54F1 /* RoundedSegmentedControl.swift in Sources */, + 8453DE5928FD32780055345C /* NotEqualWrapper.swift in Sources */, A32E1373E3671D518FFC3BC2 /* YourValidatorListViewController.swift in Sources */, 84D2F1A927744C280040C680 /* PolkadotExtensionError.swift in Sources */, 37E1E9782B9752BC50AF2476 /* YourValidatorListViewFactory.swift in Sources */, @@ -16311,11 +16362,13 @@ 36177C077867DBAEAA2675F7 /* TransferSetupViewController.swift in Sources */, 03348B3D555AA12FF2A95779 /* TransferSetupViewLayout.swift in Sources */, A5880E3789BC9E30835BDCC7 /* TransferSetupViewFactory.swift in Sources */, + 8453DE5728FD27390055345C /* Gov2SubscriptionFactory.swift in Sources */, 90ACE8690DA095E4F45494E9 /* TransferConfirmProtocols.swift in Sources */, 4E262D60ACAF44A1FD18FD1D /* TransferConfirmWireframe.swift in Sources */, BB29490A4E8472A7DB781BC4 /* TransferOnChainConfirmPresenter.swift in Sources */, 28A05FC8B129FE9016AD784D /* TransferOnChainConfirmInteractor.swift in Sources */, 841E555B282E6B0900C8438F /* StorageDecodingOperation+Init.swift in Sources */, + 8453DE5528FD24FF0055345C /* GovernanceSubscriptionProtocol.swift in Sources */, 8446F5EE2817130600B7A86C /* TitleAmountView+Style.swift in Sources */, 842643BB2878572E0031B5B5 /* TuringStakingRemoteSubscriptionService.swift in Sources */, DB37BAF11845A4E5067E07C7 /* TransferConfirmViewController.swift in Sources */, @@ -16605,6 +16658,13 @@ 1A3608A12079F00796FA9718 /* ReferendumVotersViewController.swift in Sources */, 4D44B178F1F57FD8607E8095 /* ReferendumVotersViewLayout.swift in Sources */, 89724EA9F732D0C967253597 /* ReferendumVotersViewFactory.swift in Sources */, + 1F496969FEE3E160BABDAC66 /* ReferendumVoteSetupProtocols.swift in Sources */, + F1BED07F67119E1BD052952A /* ReferendumVoteSetupWireframe.swift in Sources */, + 7E2800371BE3B166F3475E90 /* ReferendumVoteSetupPresenter.swift in Sources */, + 04D86D5341406305E60F6D18 /* ReferendumVoteSetupInteractor.swift in Sources */, + 2CEFF4C2574F0AABE0E9BF89 /* ReferendumVoteSetupViewController.swift in Sources */, + D1C4208A89633395AF2FDB74 /* ReferendumVoteSetupViewLayout.swift in Sources */, + 811096BAAA6BD237DF2769EA /* ReferendumVoteSetupViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift index 081e34fdad..1c21429ac0 100644 --- a/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift +++ b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift @@ -1,7 +1,7 @@ import Foundation import RobinHood -typealias ReferendumMetadataMapping = [Referenda.ReferendumIndex: ReferendumMetadataLocal] +typealias ReferendumMetadataMapping = [ReferendumIdLocal: ReferendumMetadataLocal] protocol GovMetadataLocalSubscriptionFactoryProtocol: AnyObject { func getMetadataProvider( diff --git a/novawallet/Common/Helpers/NotEqualWrapper.swift b/novawallet/Common/Helpers/NotEqualWrapper.swift new file mode 100644 index 0000000000..c7c931c4e9 --- /dev/null +++ b/novawallet/Common/Helpers/NotEqualWrapper.swift @@ -0,0 +1,9 @@ +import Foundation + +struct NotEqualWrapper: Equatable { + let value: V + + static func == (_: NotEqualWrapper, _: NotEqualWrapper) -> Bool { + false + } +} diff --git a/novawallet/Common/Helpers/StorageSubscriptionObserver.swift b/novawallet/Common/Helpers/StorageSubscriptionObserver.swift new file mode 100644 index 0000000000..f3ff8a2e98 --- /dev/null +++ b/novawallet/Common/Helpers/StorageSubscriptionObserver.swift @@ -0,0 +1,11 @@ +import Foundation + +final class StorageSubscriptionObserver: Observable { + let subscription: CallbackStorageSubscription + + init(subscription: CallbackStorageSubscription) { + self.subscription = subscription + + super.init(state: nil) + } +} diff --git a/novawallet/Common/Services/WebSocketService/StorageSubscription/CallbackStorageSubscription.swift b/novawallet/Common/Services/WebSocketService/StorageSubscription/CallbackStorageSubscription.swift index aa09c54fb1..6480871cf1 100644 --- a/novawallet/Common/Services/WebSocketService/StorageSubscription/CallbackStorageSubscription.swift +++ b/novawallet/Common/Services/WebSocketService/StorageSubscription/CallbackStorageSubscription.swift @@ -2,6 +2,11 @@ import Foundation import SubstrateSdk import RobinHood +struct CallbackStorageSubscriptionResult { + let value: T? + let blockHash: Data? +} + final class CallbackStorageSubscription { let request: SubscriptionRequestProtocol let runtimeService: RuntimeCodingServiceProtocol @@ -10,7 +15,8 @@ final class CallbackStorageSubscription { let repository: AnyDataProviderRepository? let callbackQueue: DispatchQueue - let callbackClosure: (Result) -> Void + let callbackClosure: ((Result) -> Void)? + let callbackWithBlockClosure: ((Result, Error>) -> Void)? private var subscriptionId: UInt16? @@ -35,6 +41,28 @@ final class CallbackStorageSubscription { self.operationQueue = operationQueue self.callbackQueue = callbackQueue self.callbackClosure = callbackClosure + callbackWithBlockClosure = nil + + encodeKeyAndSubscribe() + } + + init( + request: SubscriptionRequestProtocol, + connection: JSONRPCEngine, + runtimeService: RuntimeCodingServiceProtocol, + repository: AnyDataProviderRepository?, + operationQueue: OperationQueue, + callbackWithBlockQueue: DispatchQueue, + callbackWithBlockClosure: @escaping (Result, Error>) -> Void + ) { + self.request = request + self.connection = connection + self.runtimeService = runtimeService + self.repository = repository + self.operationQueue = operationQueue + callbackQueue = callbackWithBlockQueue + self.callbackWithBlockClosure = callbackWithBlockClosure + callbackClosure = nil encodeKeyAndSubscribe() } @@ -131,17 +159,29 @@ final class CallbackStorageSubscription { connection.cancelForIdentifier(subscriptionId) } - private func notify(result: Result) { + private func notify(result: Result, Error>) { callbackQueue.async { [weak self] in - self?.callbackClosure(result) + if let withBlockClosure = self?.callbackWithBlockClosure { + withBlockClosure(result) + } + + if let withoutBlockClosure = self?.callbackClosure { + do { + let value = try result.get().value + withoutBlockClosure(.success(value)) + } catch { + withoutBlockClosure(.failure(error)) + } + } } } - func processUpdate(_ data: Data?, blockHash _: Data?) { + func processUpdate(_ data: Data?, blockHash: Data?) { saveIfNeeded(data: data, localKey: request.localKey) guard let data = data else { - notify(result: .success(nil)) + let result = CallbackStorageSubscriptionResult(value: nil, blockHash: blockHash) + notify(result: .success(result)) return } @@ -166,7 +206,8 @@ final class CallbackStorageSubscription { decodingOperation.completionBlock = { [weak self] in do { let value = try decodingOperation.extractNoCancellableResultData() - self?.notify(result: .success(value)) + let result = CallbackStorageSubscriptionResult(value: value, blockHash: blockHash) + self?.notify(result: .success(result)) } catch { self?.notify(result: .failure(error)) } diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index 8a442d903d..a7283049c2 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -1,11 +1,17 @@ import Foundation import SoraKeystore import RobinHood +import SubstrateSdk final class GovernanceSharedState { let settings: GovernanceChainSettings let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol + let requestFactory: StorageRequestFactoryProtocol + let chainRegistry: ChainRegistryProtocol + let operationQueue: OperationQueue + + private(set) var subscriptionFactory: GovernanceSubscriptionFactoryProtocol? private(set) var blockTimeService: BlockTimeEstimationServiceProtocol? init( @@ -13,8 +19,14 @@ final class GovernanceSharedState { substrateStorageFacade: StorageFacadeProtocol = SubstrateDataStorageFacade.shared, generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol? = nil, blockTimeService: BlockTimeEstimationServiceProtocol? = nil, - internalSettings: SettingsManagerProtocol = SettingsManager.shared + internalSettings: SettingsManagerProtocol = SettingsManager.shared, + requestFactory: StorageRequestFactoryProtocol = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManager(operationQueue: OperationManagerFacade.sharedDefaultQueue) + ), + operationQueue: OperationQueue = OperationManagerFacade.sharedDefaultQueue ) { + self.chainRegistry = chainRegistry settings = GovernanceChainSettings(chainRegistry: chainRegistry, settings: internalSettings) govMetadataLocalSubscriptionFactory = GovMetadataLocalSubscriptionFactory(storageFacade: substrateStorageFacade) self.blockTimeService = blockTimeService @@ -29,9 +41,28 @@ final class GovernanceSharedState { logger: Logger.shared ) } + + self.requestFactory = requestFactory + self.operationQueue = operationQueue } func replaceBlockTimeService(_ newService: BlockTimeEstimationServiceProtocol?) { blockTimeService = newService } + + func replaceSubscriptionFactory(for chain: ChainModel?) { + guard let chainId = chain?.chainId else { + subscriptionFactory = nil + return + } + + let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) + + subscriptionFactory = Gov2SubscriptionFactory( + chainId: chainId, + operationFactory: operationFactory, + chainRegistry: chainRegistry, + operationQueue: operationQueue + ) + } } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 0a227fa378..11ab4371d0 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -2,8 +2,10 @@ import Foundation import BigInt import SubstrateSdk +typealias ReferendumIdLocal = UInt + struct ReferendumLocal { - let index: UInt + let index: ReferendumIdLocal let state: ReferendumStateLocal let proposer: AccountId? } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index ff37d5c684..844106f20c 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -35,8 +35,9 @@ final class Gov2OperationFactory { private func createEnacmentTimeFetchWrapper( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol - ) -> CompoundOperationWrapper<[Referenda.ReferendumIndex: BlockNumber]> { + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper<[ReferendumIdLocal: BlockNumber]> { let keysClosure: () throws -> [SchedulerTaskName] = { let referendums = try referendumOperation.extractNoCancellableResultData() @@ -57,21 +58,22 @@ final class Gov2OperationFactory { engine: connection, keyParams: keysClosure, factory: { try codingFactoryOperation.extractNoCancellableResultData() }, - storagePath: OnChainScheduler.lookupTaskPath + storagePath: OnChainScheduler.lookupTaskPath, + at: blockHash ) enactmentWrapper.addDependency(operations: [codingFactoryOperation]) - let mapOperation = ClosureOperation<[Referenda.ReferendumIndex: BlockNumber]> { + let mapOperation = ClosureOperation<[ReferendumIdLocal: BlockNumber]> { let keys = try keysClosure() let results = try enactmentWrapper.targetOperation.extractNoCancellableResultData() - return zip(keys, results).reduce(into: [Referenda.ReferendumIndex: BlockNumber]()) { accum, keyResult in + return zip(keys, results).reduce(into: [ReferendumIdLocal: BlockNumber]()) { accum, keyResult in guard let when = keyResult.1.value?.when else { return } - accum[keyResult.0.index] = when + accum[ReferendumIdLocal(keyResult.0.index)] = when } } @@ -85,7 +87,7 @@ final class Gov2OperationFactory { private func createReferendumMapOperation( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, additionalInfoOperation: BaseOperation, - enactmentsOperation: BaseOperation<[Referenda.ReferendumIndex: BlockNumber]> + enactmentsOperation: BaseOperation<[ReferendumIdLocal: BlockNumber]> ) -> BaseOperation<[ReferendumLocal]> { ClosureOperation<[ReferendumLocal]> { let remoteReferendums = try referendumOperation.extractNoCancellableResultData() @@ -95,12 +97,12 @@ final class Gov2OperationFactory { let mappingFactory = Gov2LocalMappingFactory() return remoteReferendums.compactMap { keyedReferendum in - let referendumIndex = keyedReferendum.key.referendumIndex + let referendumIndex = ReferendumIdLocal(keyedReferendum.key.referendumIndex) let remoteReferendum = keyedReferendum.value return mappingFactory.mapRemote( referendum: remoteReferendum, - index: referendumIndex, + index: Referenda.ReferendumIndex(referendumIndex), additionalInfo: additionalInfo, enactmentBlock: enactments[referendumIndex] ) @@ -110,7 +112,8 @@ final class Gov2OperationFactory { private func createAdditionalInfoWrapper( from connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? ) -> CompoundOperationWrapper { let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() @@ -138,7 +141,8 @@ final class Gov2OperationFactory { requestFactory.queryItem( engine: connection, factory: { try codingFactoryOperation.extractNoCancellableResultData() }, - storagePath: .totalIssuance + storagePath: .totalIssuance, + at: blockHash ) let fetchOperations = [tracksOperation, undecidingTimeoutOperation] + totalIssuanceWrapper.allOperations @@ -187,12 +191,17 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { referendumWrapper.addDependency(operations: [codingFactoryOperation]) - let additionalInfoWrapper = createAdditionalInfoWrapper(from: connection, runtimeProvider: runtimeProvider) + let additionalInfoWrapper = createAdditionalInfoWrapper( + from: connection, + runtimeProvider: runtimeProvider, + blockHash: nil + ) let enactmentsWrapper = createEnacmentTimeFetchWrapper( dependingOn: referendumWrapper.targetOperation, connection: connection, - runtimeProvider: runtimeProvider + runtimeProvider: runtimeProvider, + blockHash: nil ) enactmentsWrapper.addDependency(wrapper: referendumWrapper) @@ -215,21 +224,27 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { func fetchReferendumWrapper( for remoteReferendum: ReferendumInfo, - index: Referenda.ReferendumIndex, + index: ReferendumIdLocal, connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? ) -> CompoundOperationWrapper { - let additionalInfoWrapper = createAdditionalInfoWrapper(from: connection, runtimeProvider: runtimeProvider) + let additionalInfoWrapper = createAdditionalInfoWrapper( + from: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) let referendumOperation = ClosureOperation<[ReferendumIndexKey: ReferendumInfo]> { - let referendumIndexKey = ReferendumIndexKey(referendumIndex: index) + let referendumIndexKey = ReferendumIndexKey(referendumIndex: Referenda.ReferendumIndex(index)) return [referendumIndexKey: remoteReferendum] } let enactmentsWrapper = createEnacmentTimeFetchWrapper( dependingOn: referendumOperation, connection: connection, - runtimeProvider: runtimeProvider + runtimeProvider: runtimeProvider, + blockHash: blockHash ) enactmentsWrapper.addDependency(operations: [referendumOperation]) @@ -263,8 +278,9 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { func fetchAccountVotesWrapper( for accountId: AccountId, from connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol - ) -> CompoundOperationWrapper<[Referenda.ReferendumIndex: ReferendumAccountVoteLocal]> { + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper<[UInt: ReferendumAccountVoteLocal]> { let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() let request = MapRemoteStorageRequest(storagePath: ConvictionVoting.votingFor) { @@ -276,19 +292,20 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { engine: connection, request: request, storagePath: ConvictionVoting.votingFor, - factory: { try codingFactoryOperation.extractNoCancellableResultData() } + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + at: blockHash ) votesWrapper.addDependency(operations: [codingFactoryOperation]) - let mappingOperation = ClosureOperation<[Referenda.ReferendumIndex: ReferendumAccountVoteLocal]> { + let mappingOperation = ClosureOperation<[UInt: ReferendumAccountVoteLocal]> { let votes = try votesWrapper.targetOperation.extractNoCancellableResultData().values - return votes.reduce(into: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]()) { result, voting in + return votes.reduce(into: [UInt: ReferendumAccountVoteLocal]()) { result, voting in switch voting { case let .casting(castingVoting): castingVoting.votes.forEach { vote in - result[vote.pollIndex] = ReferendumAccountVoteLocal(accountVote: vote.accountVote) + result[UInt(vote.pollIndex)] = ReferendumAccountVoteLocal(accountVote: vote.accountVote) } case .delegating, .unknown: break @@ -304,7 +321,7 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { } func fetchVotersWrapper( - for referendumIndex: Referenda.ReferendumIndex, + for referendumIndex: ReferendumIdLocal, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol ) -> CompoundOperationWrapper<[ReferendumVoterLocal]> { diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift index 6095f0c48f..f2b973c277 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -8,21 +8,15 @@ protocol ReferendumsOperationFactoryProtocol { runtimeProvider: RuntimeProviderProtocol ) -> CompoundOperationWrapper<[ReferendumLocal]> - func fetchReferendumWrapper( - for remoteReferendum: ReferendumInfo, - index: Referenda.ReferendumIndex, - connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol - ) -> CompoundOperationWrapper - func fetchAccountVotesWrapper( for accountId: AccountId, from connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol - ) -> CompoundOperationWrapper<[Referenda.ReferendumIndex: ReferendumAccountVoteLocal]> + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper<[UInt: ReferendumAccountVoteLocal]> func fetchVotersWrapper( - for referendumIndex: Referenda.ReferendumIndex, + for referendumIndex: ReferendumIdLocal, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol ) -> CompoundOperationWrapper<[ReferendumVoterLocal]> diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift index 4b45195ba2..1aacb619fd 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift @@ -3,6 +3,7 @@ import Foundation enum ReferendumDetailsInteractorError: Error { case referendumFailed(_ internalError: Error) case actionDetailsFailed(_ internalError: Error) + case accountVotesFailed(_ internalError: Error) case metadataFailed(_ internalError: Error) case identitiesFailed(_ internalError: Error) case priceFailed(_ internalError: Error) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index e3befad77d..0ce0f848cc 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -7,6 +7,8 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { private(set) var referendum: ReferendumLocal private(set) var actionDetails: ReferendumActionLocal? + + let selectedAccount: ChainAccountResponse let chain: ChainModel let actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol let connection: JSONRPCEngine @@ -15,22 +17,21 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { let blockTimeService: BlockTimeEstimationServiceProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol + let referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol - let referendumsOperationFactory: ReferendumsOperationFactoryProtocol let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? private var metadataProvider: AnySingleValueProvider? private var blockNumberSubscription: AnyDataProvider? - private var referendumSubscription: CallbackStorageSubscription? - private var referendumCancellable: CancellableCall? private var identitiesCancellable: CancellableCall? private var actionDetailsCancellable: CancellableCall? private var blockTimeCancellable: CancellableCall? init( referendum: ReferendumLocal, + selectedAccount: ChainAccountResponse, chain: ChainModel, actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol, connection: JSONRPCEngine, @@ -40,11 +41,12 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol, - referendumsOperationFactory: ReferendumsOperationFactoryProtocol, + referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, currencyManager: CurrencyManagerProtocol, operationQueue: OperationQueue ) { self.referendum = referendum + self.selectedAccount = selectedAccount self.chain = chain self.actionDetailsOperationFactory = actionDetailsOperationFactory self.connection = connection @@ -54,84 +56,58 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory self.blockTimeService = blockTimeService self.govMetadataLocalSubscriptionFactory = govMetadataLocalSubscriptionFactory - self.referendumsOperationFactory = referendumsOperationFactory + self.referendumsSubscriptionFactory = referendumsSubscriptionFactory self.operationQueue = operationQueue self.currencyManager = currencyManager } deinit { - clear(cancellable: &referendumCancellable) clear(cancellable: &identitiesCancellable) clear(cancellable: &actionDetailsCancellable) clear(cancellable: &blockTimeCancellable) - referendumSubscription = nil + referendumsSubscriptionFactory.unsubscribeFromReferendum(self, referendumIndex: referendum.index) + referendumsSubscriptionFactory.unsubscribeFromAccountVotes(self, accountId: selectedAccount.accountId) } - private func provideReferendum(for referendumInfo: ReferendumInfo) { - clear(cancellable: &referendumCancellable) - - let wrapper = referendumsOperationFactory.fetchReferendumWrapper( - for: referendumInfo, - index: Referenda.ReferendumIndex(referendum.index), - connection: connection, - runtimeProvider: runtimeProvider - ) - - wrapper.targetOperation.completionBlock = { [weak self] in - DispatchQueue.main.async { - guard wrapper === self?.referendumCancellable else { - return - } - - self?.referendumCancellable = nil + private func subscribeReferendum() { + referendumsSubscriptionFactory.unsubscribeFromReferendum(self, referendumIndex: referendum.index) - do { - let referendum = try wrapper.targetOperation.extractNoCancellableResultData() + referendumsSubscriptionFactory.subscribeToReferendum( + self, + referendumIndex: referendum.index + ) { [weak self] result in + switch result { + case let .success(referendumResult): + if let referendum = referendumResult.value { self?.referendum = referendum - self?.presenter?.didReceiveReferendum(referendum) - } catch { - self?.presenter?.didReceiveError(.referendumFailed(error)) } + case let .failure(error): + self?.presenter?.didReceiveError(.referendumFailed(error)) + case .none: + break } } - - referendumCancellable = wrapper - - operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) - } - - private func handleReferendumSubscription(result: Result) { - switch result { - case let .success(referendumInfo): - if let referendumInfo = referendumInfo { - provideReferendum(for: referendumInfo) - } - case let .failure(error): - presenter?.didReceiveError(.referendumFailed(error)) - } } - private func subscribeReferendum() { - let referendumIndex = referendum.index - - let request = MapSubscriptionRequest( - storagePath: Referenda.referendumInfo, - localKey: "" - ) { - StringScaleMapper(value: referendumIndex) - } + private func subscribeAccountVotes() { + referendumsSubscriptionFactory.unsubscribeFromAccountVotes(self, accountId: selectedAccount.accountId) - referendumSubscription = CallbackStorageSubscription( - request: request, - connection: connection, - runtimeService: runtimeProvider, - repository: nil, - operationQueue: operationQueue, - callbackQueue: .main + referendumsSubscriptionFactory.subscribeToAccountVotes( + self, + accountId: selectedAccount.accountId ) { [weak self] result in - self?.handleReferendumSubscription(result: result) + switch result { + case let .success(votesResult): + if let votes = votesResult.value, let referendumId = self?.referendum.index { + self?.presenter?.didReceiveAccountVotes(votes[referendumId]) + } + case let .failure(error): + self?.presenter?.didReceiveError(.accountVotesFailed(error)) + case .none: + break + } } } @@ -254,6 +230,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { blockNumberSubscription = subscribeToBlockNumber(for: chain.chainId) subscribeReferendum() + subscribeAccountVotes() metadataProvider = subscribeGovMetadata(for: chain) } @@ -311,7 +288,7 @@ extension ReferendumDetailsInteractor: GovMetadataLocalStorageSubscriber, GovMet func handleGovMetadata(result: Result, chain _: ChainModel) { switch result { case let .success(mapping): - let metadata = mapping?[Referenda.ReferendumIndex(referendum.index)] + let metadata = mapping?[referendum.index] presenter?.didReceiveMetadata(metadata) case let .failure(error): presenter?.didReceiveError(.metadataFailed(error)) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index ec205b9705..3840b157aa 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -11,6 +11,7 @@ final class ReferendumDetailsPresenter { private var referendum: ReferendumLocal private var actionDetails: ReferendumActionLocal? + private var accountVotes: ReferendumAccountVoteLocal? private var referendumMetadata: ReferendumMetadataLocal? private var identities: [AccountAddress: AccountIdentity]? private var price: PriceData? @@ -53,6 +54,12 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol logger.info("Did receive action details") } + func didReceiveAccountVotes(_ votes: ReferendumAccountVoteLocal?) { + accountVotes = votes + + logger.info("Did receive account votes") + } + func didReceiveMetadata(_ referendumMetadata: ReferendumMetadataLocal?) { self.referendumMetadata = referendumMetadata @@ -87,7 +94,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol logger.error("Did receive error: \(error)") switch error { - case .referendumFailed, .priceFailed, .blockNumberFailed, .metadataFailed: + case .referendumFailed, .accountVotesFailed, .priceFailed, .blockNumberFailed, .metadataFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in self?.interactor.remakeSubscriptions() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index cc34057ebc..3209f479fa 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -15,6 +15,7 @@ protocol ReferendumDetailsInteractorInputProtocol: AnyObject { protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { func didReceiveReferendum(_ referendum: ReferendumLocal) func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) + func didReceiveAccountVotes(_ votes: ReferendumAccountVoteLocal?) func didReceiveMetadata(_ referendumMetadata: ReferendumMetadataLocal?) func didReceiveIdentities(_ identities: [AccountAddress: AccountIdentity]) func didReceivePrice(_ price: PriceData?) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 2655152085..7d88e96584 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -44,16 +44,19 @@ struct ReferendumDetailsViewFactory { currencyManager: CurrencyManagerProtocol, state: GovernanceSharedState ) -> ReferendumDetailsInteractor? { - guard let chain = state.settings.value else { + guard + let chain = state.settings.value, + let selectedAccount = SelectedWalletSettings.shared.value.fetch(for: chain.accountRequest()) else { return nil } - let chainRegistry = ChainRegistryFacade.sharedRegistry + let chainRegistry = state.chainRegistry guard let connection = chainRegistry.getConnection(for: chain.chainId), let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId), - let blockTimeService = state.blockTimeService else { + let blockTimeService = state.blockTimeService, + let subscriptionFactory = state.subscriptionFactory else { return nil } @@ -73,10 +76,9 @@ struct ReferendumDetailsViewFactory { emptyIdentitiesWhenNoStorage: true ) - let referendumsOperationFactory = Gov2OperationFactory(requestFactory: requestFactory) - return ReferendumDetailsInteractor( referendum: referendum, + selectedAccount: selectedAccount, chain: chain, actionDetailsOperationFactory: actionDetailsOperationFactory, connection: connection, @@ -86,7 +88,7 @@ struct ReferendumDetailsViewFactory { priceLocalSubscriptionFactory: PriceProviderFactory.shared, generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, govMetadataLocalSubscriptionFactory: state.govMetadataLocalSubscriptionFactory, - referendumsOperationFactory: referendumsOperationFactory, + referendumsSubscriptionFactory: subscriptionFactory, currencyManager: currencyManager, operationQueue: OperationManagerFacade.sharedDefaultQueue ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift new file mode 100644 index 0000000000..e8aeac2f3d --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift @@ -0,0 +1,7 @@ +import UIKit + +final class ReferendumVoteSetupInteractor { + weak var presenter: ReferendumVoteSetupInteractorOutputProtocol? +} + +extension ReferendumVoteSetupInteractor: ReferendumVoteSetupInteractorInputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift new file mode 100644 index 0000000000..732ad4c40b --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -0,0 +1,21 @@ +import Foundation + +final class ReferendumVoteSetupPresenter { + weak var view: ReferendumVoteSetupViewProtocol? + let wireframe: ReferendumVoteSetupWireframeProtocol + let interactor: ReferendumVoteSetupInteractorInputProtocol + + init( + interactor: ReferendumVoteSetupInteractorInputProtocol, + wireframe: ReferendumVoteSetupWireframeProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + } +} + +extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { + func setup() {} +} + +extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift new file mode 100644 index 0000000000..9e168a3567 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -0,0 +1,11 @@ +protocol ReferendumVoteSetupViewProtocol: AnyObject {} + +protocol ReferendumVoteSetupPresenterProtocol: AnyObject { + func setup() +} + +protocol ReferendumVoteSetupInteractorInputProtocol: AnyObject {} + +protocol ReferendumVoteSetupInteractorOutputProtocol: AnyObject {} + +protocol ReferendumVoteSetupWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift new file mode 100644 index 0000000000..acaaf39614 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -0,0 +1,29 @@ +import UIKit + +final class ReferendumVoteSetupViewController: UIViewController { + typealias RootViewType = ReferendumVoteSetupViewLayout + + let presenter: ReferendumVoteSetupPresenterProtocol + + init(presenter: ReferendumVoteSetupPresenterProtocol) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = ReferendumVoteSetupViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + presenter.setup() + } +} + +extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift new file mode 100644 index 0000000000..5a532d32e3 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -0,0 +1,17 @@ +import Foundation + +struct ReferendumVoteSetupViewFactory { + static func createView() -> ReferendumVoteSetupViewProtocol? { + let interactor = ReferendumVoteSetupInteractor() + let wireframe = ReferendumVoteSetupWireframe() + + let presenter = ReferendumVoteSetupPresenter(interactor: interactor, wireframe: wireframe) + + let view = ReferendumVoteSetupViewController(presenter: presenter) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift new file mode 100644 index 0000000000..15ca69685d --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -0,0 +1,12 @@ +import UIKit + +final class ReferendumVoteSetupViewLayout: UIView { + override init(frame: CGRect) { + super.init(frame: frame) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift new file mode 100644 index 0000000000..9b8f1b4f23 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class ReferendumVoteSetupWireframe: ReferendumVoteSetupWireframeProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift index 572e7e76b5..2061e487e6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersInteractor.swift @@ -7,14 +7,14 @@ final class ReferendumVotersInteractor { let referendumsOperationFactory: ReferendumsOperationFactoryProtocol let chain: ChainModel - let referendumIndex: Referenda.ReferendumIndex + let referendumIndex: ReferendumIdLocal let identityOperationFactory: IdentityOperationFactoryProtocol let connection: JSONRPCEngine let runtimeProvider: RuntimeProviderProtocol let operationQueue: OperationQueue init( - referendumIndex: Referenda.ReferendumIndex, + referendumIndex: ReferendumIdLocal, chain: ChainModel, referendumsOperationFactory: ReferendumsOperationFactoryProtocol, identityOperationFactory: IdentityOperationFactoryProtocol, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift index ab075f0b66..e7f990c5f7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift @@ -78,7 +78,7 @@ struct ReferendumVotersViewFactory { ) return ReferendumVotersInteractor( - referendumIndex: Referenda.ReferendumIndex(referendum.index), + referendumIndex: referendum.index, chain: chain, referendumsOperationFactory: referendumsOperationFactory, identityOperationFactory: identityOperationFactory, diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 7390dc0deb..9c59a8223e 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -71,6 +71,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani clear(singleValueProvider: &metadataProvider) clearBlockTimeService() + clearSubscriptionFactory() blockNumberSubscription = nil @@ -88,6 +89,10 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani governanceState.replaceBlockTimeService(nil) } + private func clearSubscriptionFactory() { + governanceState.replaceSubscriptionFactory(for: nil) + } + private func continueSetup() { applicationHandler.delegate = self @@ -115,6 +120,8 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani setupBlockTimeService(for: chain) provideBlockTime() + setupSubscriptionFactory(for: chain) + subscribeToBlockNumber(for: chain) subscribeToMetadata(for: chain) } @@ -131,6 +138,10 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani } } + private func setupSubscriptionFactory(for chain: ChainModel) { + governanceState.replaceSubscriptionFactory(for: chain) + } + private func subscribeToBlockNumber(for chain: ChainModel) { guard blockNumberSubscription == nil else { return @@ -276,7 +287,8 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani let wrapper = referendumsOperationFactory.fetchAccountVotesWrapper( for: accountId, from: connection, - runtimeProvider: runtimeProvider + runtimeProvider: runtimeProvider, + blockHash: nil ) wrapper.targetOperation.completionBlock = { [weak self] in diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 332af7ebff..8da9f0f36f 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -16,7 +16,7 @@ final class ReferendumsPresenter { private var price: PriceData? private var referendums: [ReferendumLocal]? private var referendumsMetadata: ReferendumMetadataMapping? - private var votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]? + private var votes: [UInt: ReferendumAccountVoteLocal]? private var blockNumber: BlockNumber? private var blockTime: BlockTime? @@ -194,7 +194,7 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { } extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { - func didReceiveVotes(_ votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]) { + func didReceiveVotes(_ votes: [UInt: ReferendumAccountVoteLocal]) { self.votes = votes } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 139ad6279f..7def851ae8 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -25,7 +25,7 @@ protocol ReferendumsInteractorInputProtocol: AnyObject { protocol ReferendumsInteractorOutputProtocol: AnyObject { func didReceiveReferendums(_ referendums: [ReferendumLocal]) func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) - func didReceiveVotes(_ votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal]) + func didReceiveVotes(_ votes: [ReferendumIdLocal: ReferendumAccountVoteLocal]) func didReceiveSelectedChain(_ chain: ChainModel) func didReceiveAssetBalance(_ balance: AssetBalance?) func didReceivePrice(_ price: PriceData?) diff --git a/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift b/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift new file mode 100644 index 0000000000..cfd2d041ad --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift @@ -0,0 +1,299 @@ +import Foundation +import SubstrateSdk +import RobinHood + +final class Gov2SubscriptionFactory: AnyCancellableCleaning { + typealias ReferendumState = NotEqualWrapper + typealias VotesState = NotEqualWrapper + typealias ReferendumWrapper = StorageSubscriptionObserver + typealias VotesWrapper = StorageSubscriptionObserver + + private(set) var referendums: [ReferendumIdLocal: ReferendumWrapper] = [:] + private(set) var votes: [AccountId: VotesWrapper] = [:] + private(set) var cancellables: [String: CancellableCall] = [:] + + let operationFactory: Gov2OperationFactory + let chainRegistry: ChainRegistryProtocol + let operationQueue: OperationQueue + let chainId: ChainModel.Id + + init( + chainId: ChainModel.Id, + operationFactory: Gov2OperationFactory, + chainRegistry: ChainRegistryProtocol, + operationQueue: OperationQueue + ) { + self.chainId = chainId + self.operationFactory = operationFactory + self.chainRegistry = chainRegistry + self.operationQueue = operationQueue + } + + private func handleReferendumResult( + _ result: Result, Error>, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + referendumIndex: ReferendumIdLocal + ) { + guard let wrapper = referendums[referendumIndex] else { + return + } + + switch result { + case let .success(result): + if let referendumInfo = result.value { + handleReferendum( + for: referendumInfo, + connection: connection, + runtimeProvider: runtimeProvider, + referendumIndex: referendumIndex, + blockHash: result.blockHash + ) + } else { + let value = CallbackStorageSubscriptionResult(value: nil, blockHash: nil) + wrapper.state = NotEqualWrapper(value: .success(value)) + } + case let .failure(error): + wrapper.state = NotEqualWrapper(value: .failure(error)) + } + } + + private func handleReferendum( + for referendumInfo: ReferendumInfo, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + referendumIndex: ReferendumIdLocal, + blockHash: Data? + ) { + let cancellableKey = "referendum-\(referendumIndex)" + clear(cancellable: &cancellables[cancellableKey]) + + let wrapper = operationFactory.fetchReferendumWrapper( + for: referendumInfo, + index: referendumIndex, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.cancellables[cancellableKey] else { + return + } + + self?.cancellables[cancellableKey] = nil + + do { + let referendum = try wrapper.targetOperation.extractNoCancellableResultData() + let value = CallbackStorageSubscriptionResult( + value: referendum, + blockHash: blockHash + ) + + self?.referendums[referendumIndex]?.state = NotEqualWrapper(value: .success(value)) + } catch { + self?.referendums[referendumIndex]?.state = NotEqualWrapper(value: .failure(error)) + } + } + } + + cancellables[cancellableKey] = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } + + private func handleVotesResult( + _ result: Result, Error>, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + accountId: AccountId + ) { + guard let wrapper = votes[accountId] else { + return + } + + switch result { + case let .success(result): + handleVotes( + for: accountId, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: result.blockHash + ) + case let .failure(error): + wrapper.state = NotEqualWrapper(value: .failure(error)) + } + } + + private func handleVotes( + for accountId: AccountId, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) { + let cancellableKey = "votes-\(accountId.toHex())" + clear(cancellable: &cancellables[cancellableKey]) + + let wrapper = operationFactory.fetchAccountVotesWrapper( + for: accountId, + from: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.cancellables[cancellableKey] else { + return + } + + self?.cancellables[cancellableKey] = nil + + do { + let votes = try wrapper.targetOperation.extractNoCancellableResultData() + let value = CallbackStorageSubscriptionResult<[UInt: ReferendumAccountVoteLocal]>( + value: votes, + blockHash: blockHash + ) + + self?.votes[accountId]?.state = NotEqualWrapper(value: .success(value)) + } catch { + self?.votes[accountId]?.state = NotEqualWrapper(value: .failure(error)) + } + } + } + + cancellables[cancellableKey] = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } +} + +extension Gov2SubscriptionFactory: GovernanceSubscriptionFactoryProtocol { + func subscribeToReferendum( + _ target: AnyObject, + referendumIndex: ReferendumIdLocal, + notificationClosure: @escaping (ReferendumSubscriptionResult?) -> Void + ) { + let subscriptionWrapper: ReferendumWrapper + + if let wrapper = referendums[referendumIndex] { + subscriptionWrapper = wrapper + } else { + let request = MapSubscriptionRequest(storagePath: Referenda.referendumInfo, localKey: "") { + StringScaleMapper(value: referendumIndex) + } + + guard let connection = chainRegistry.getConnection(for: chainId) else { + notificationClosure(.failure(ChainRegistryError.connectionUnavailable)) + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + notificationClosure(.failure(ChainRegistryError.runtimeMetadaUnavailable)) + return + } + + let subscription = CallbackStorageSubscription( + request: request, + connection: connection, + runtimeService: runtimeProvider, + repository: nil, + operationQueue: operationQueue, + callbackWithBlockQueue: .main + ) { [weak self] result in + self?.handleReferendumResult( + result, + connection: connection, + runtimeProvider: runtimeProvider, + referendumIndex: referendumIndex + ) + } + + subscriptionWrapper = ReferendumWrapper(subscription: subscription) + referendums[referendumIndex] = subscriptionWrapper + } + + notificationClosure(subscriptionWrapper.state?.value) + + subscriptionWrapper.addObserver(with: target) { _, newValueWrapper in + notificationClosure(newValueWrapper?.value) + } + } + + func unsubscribeFromReferendum(_: AnyObject, referendumIndex: ReferendumIdLocal) { + guard let subscriptionWrapper = referendums[referendumIndex] else { + return + } + + subscriptionWrapper.removeObserver(by: self) + + if subscriptionWrapper.observers.isEmpty { + referendums[referendumIndex] = nil + } + } + + func subscribeToAccountVotes( + _ target: AnyObject, + accountId: AccountId, + notificationClosure: @escaping (ReferendumVotesSubscriptionResult?) -> Void + ) { + let subscriptionWrapper: VotesWrapper + + if let wrapper = votes[accountId] { + subscriptionWrapper = wrapper + } else { + let request = MapSubscriptionRequest(storagePath: ConvictionVoting.trackLocksFor, localKey: "") { + BytesCodable(wrappedValue: accountId) + } + + guard let connection = chainRegistry.getConnection(for: chainId) else { + notificationClosure(.failure(ChainRegistryError.connectionUnavailable)) + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + notificationClosure(.failure(ChainRegistryError.runtimeMetadaUnavailable)) + return + } + + let subscription = CallbackStorageSubscription( + request: request, + connection: connection, + runtimeService: runtimeProvider, + repository: nil, + operationQueue: operationQueue, + callbackWithBlockQueue: .main + ) { [weak self] result in + self?.handleVotesResult( + result, + connection: connection, + runtimeProvider: runtimeProvider, + accountId: accountId + ) + } + + subscriptionWrapper = VotesWrapper(subscription: subscription) + votes[accountId] = subscriptionWrapper + } + + notificationClosure(subscriptionWrapper.state?.value) + + subscriptionWrapper.addObserver(with: target) { _, newValueWrapper in + notificationClosure(newValueWrapper?.value) + } + } + + func unsubscribeFromAccountVotes(_: AnyObject, accountId: AccountId) { + guard let subscriptionWrapper = votes[accountId] else { + return + } + + subscriptionWrapper.removeObserver(by: self) + + if subscriptionWrapper.observers.isEmpty { + votes[accountId] = nil + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift b/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift new file mode 100644 index 0000000000..6abab62439 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift @@ -0,0 +1,26 @@ +import Foundation + +typealias ReferendumSubscriptionResult = Result, Error> + +typealias ReferendumVotesSubscriptionResult = Result< + CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]>, + Error +> + +protocol GovernanceSubscriptionFactoryProtocol { + func subscribeToReferendum( + _ target: AnyObject, + referendumIndex: UInt, + notificationClosure: @escaping (ReferendumSubscriptionResult?) -> Void + ) + + func unsubscribeFromReferendum(_ target: AnyObject, referendumIndex: ReferendumIdLocal) + + func subscribeToAccountVotes( + _ target: AnyObject, + accountId: AccountId, + notificationClosure: @escaping (ReferendumVotesSubscriptionResult?) -> Void + ) + + func unsubscribeFromAccountVotes(_ target: AnyObject, accountId: AccountId) +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index b853709de2..8c75e64a1c 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -4,8 +4,8 @@ import BigInt struct ReferendumsModelFactoryInput { let referendums: [ReferendumLocal] - let metadataMapping: [Referenda.ReferendumIndex: ReferendumMetadataLocal]? - let votes: [Referenda.ReferendumIndex: ReferendumAccountVoteLocal] + let metadataMapping: [ReferendumIdLocal: ReferendumMetadataLocal]? + let votes: [ReferendumIdLocal: ReferendumAccountVoteLocal] let chainInfo: ChainInformation let locale: Locale @@ -366,14 +366,13 @@ extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { var completed: [ReferendumsCellViewModel] = [] input.referendums.forEach { referendum in - let index = Referenda.ReferendumIndex(referendum.index) - let metadata = input.metadataMapping?[index] + let metadata = input.metadataMapping?[referendum.index] let params = StatusParams( referendum: referendum, metadata: metadata, chainInfo: input.chainInfo, - votes: input.votes[index] + votes: input.votes[referendum.index] ) let model = createReferendumCellViewModel( From 4718eee805049743d6d51fb4e6d711aea0b9c6f6 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 17 Oct 2022 18:29:15 +0500 Subject: [PATCH 054/229] fix subscription --- .../ReferendumDetails/ReferendumDetailsInteractor.swift | 9 +++++++++ .../Governance/Referendums/ReferendumsInteractor.swift | 4 ++++ .../Governance/Referendums/ReferendumsPresenter.swift | 4 +++- .../Governance/Referendums/ReferendumsProtocols.swift | 2 ++ .../Governance/Referendums/ReferendumsWireframe.swift | 8 ++++++++ .../Subscription/Gov2SubscriptionFactory.swift | 6 +++--- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 0ce0f848cc..75ba3c54d1 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -256,6 +256,15 @@ extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol } func remakeSubscriptions() { + priceProvider?.removeObserver(self) + priceProvider = nil + + metadataProvider?.removeObserver(self) + metadataProvider = nil + + blockNumberSubscription?.removeObserver(self) + blockNumberSubscription = nil + makeSubscriptions() } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 9c59a8223e..837631a783 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -331,6 +331,9 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { func remakeSubscriptions() { clear() + blockNumberSubscription?.removeObserver(self) + blockNumberSubscription = nil + if let chain = governanceState.settings.value { let accountResponse = selectedMetaAccount.fetch(for: chain.accountRequest()) @@ -360,6 +363,7 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { } func putOffline() { + blockNumberSubscription?.removeObserver(self) blockNumberSubscription = nil } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 8da9f0f36f..badaa0369a 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -162,6 +162,8 @@ extension ReferendumsPresenter: ReferendumsPresenterProtocol { guard let referendum = referendums?.first(where: { $0.index == referendumIndex }) else { return } + + wireframe.showReferendumDetails(from: view, referendum: referendum) } } @@ -194,7 +196,7 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { } extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { - func didReceiveVotes(_ votes: [UInt: ReferendumAccountVoteLocal]) { + func didReceiveVotes(_ votes: [ReferendumIdLocal: ReferendumAccountVoteLocal]) { self.votes = votes } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 7def851ae8..981c0a843d 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -40,4 +40,6 @@ protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, Commo delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId? ) + + func showReferendumDetails(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index 75c34588c2..979a8d2eb5 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -30,4 +30,12 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { view?.controller.present(navigationController, animated: true, completion: nil) } + + func showReferendumDetails(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) { + guard let detailsView = ReferendumDetailsViewFactory.createView(for: referendum, state: state) else { + return + } + + view?.controller.navigationController?.pushViewController(detailsView.controller, animated: true) + } } diff --git a/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift b/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift index cfd2d041ad..890e21d38a 100644 --- a/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift +++ b/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift @@ -6,7 +6,7 @@ final class Gov2SubscriptionFactory: AnyCancellableCleaning { typealias ReferendumState = NotEqualWrapper typealias VotesState = NotEqualWrapper typealias ReferendumWrapper = StorageSubscriptionObserver - typealias VotesWrapper = StorageSubscriptionObserver + typealias VotesWrapper = StorageSubscriptionObserver<[ConvictionVoting.ClassLock], VotesState> private(set) var referendums: [ReferendumIdLocal: ReferendumWrapper] = [:] private(set) var votes: [AccountId: VotesWrapper] = [:] @@ -104,7 +104,7 @@ final class Gov2SubscriptionFactory: AnyCancellableCleaning { } private func handleVotesResult( - _ result: Result, Error>, + _ result: Result, Error>, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, accountId: AccountId @@ -258,7 +258,7 @@ extension Gov2SubscriptionFactory: GovernanceSubscriptionFactoryProtocol { return } - let subscription = CallbackStorageSubscription( + let subscription = CallbackStorageSubscription<[ConvictionVoting.ClassLock]>( request: request, connection: connection, runtimeService: runtimeProvider, From 9b47e92dea113b0b2157a9d63c36c2a0f0c574d5 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 18 Oct 2022 13:26:31 +0300 Subject: [PATCH 055/229] added navigation --- .../ReferendumDetailsProtocols.swift | 2 +- .../ReferendumDetailsViewLayout.swift | 28 ++++++++- .../MyPlayground.playground/Contents.swift | 60 ++++++++++++++++--- .../View/ReferendumDetailsTitleView.swift | 35 ++++++----- .../Referendums/ReferendumsPresenter.swift | 13 +++- .../Referendums/ReferendumsProtocols.swift | 10 +++- .../Referendums/ReferendumsViewManager.swift | 4 ++ .../Referendums/ReferendumsWireframe.swift | 18 ++++++ .../Governance/View/ReferendumInfoView.swift | 9 ++- 9 files changed, 146 insertions(+), 33 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index e4ad87019f..c86f6febdd 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -1,4 +1,4 @@ -protocol ReferendumDetailsViewProtocol: AnyObject {} +protocol ReferendumDetailsViewProtocol: AnyObject, ControllerBackedProtocol {} protocol ReferendumDetailsPresenterProtocol: AnyObject { func setup() diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index c3a37fd1e1..9035ff28c6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -8,9 +8,16 @@ final class ReferendumDetailsViewLayout: UIView { view.stackView.alignment = .fill return view }() - + + let titleView = ReferendumDetailsTitleView() + let votingStatusView = ReferendumVotingStatusView() + let dAppsTableView = StackTableView() + let timelineTableView = ReferendumTimelineView() + override init(frame: CGRect) { super.init(frame: frame) + + setupLayout() } @available(*, unavailable) @@ -23,5 +30,24 @@ final class ReferendumDetailsViewLayout: UIView { containerView.snp.makeConstraints { $0.edges.equalToSuperview() } + + containerView.stackView.addArrangedSubview(titleView) + containerView.stackView.setCustomSpacing(16, after: titleView) + + containerView.stackView.addArrangedSubview(votingStatusView) + containerView.stackView.setCustomSpacing(12, after: votingStatusView) + + containerView.stackView.addArrangedSubview(timelineTableView) + containerView.stackView.setCustomSpacing(12, after: dAppsTableView) + } + + func setDApps(models: [ReferendumDAppView.Model]) { + models.forEach { + let dAppView = ReferendumDAppCellView() + dAppView.rowContentView.bind(viewModel: $0) + dAppsTableView.addArrangedSubview(dAppView) + } } } + +final class ReferendumDAppCellView: RowView, StackTableViewCellProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift index 43a473282e..902ba9fc76 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift @@ -2,6 +2,7 @@ import UIKit import SnapKit +import SubstrateSdk import PlaygroundSupport private func registerFonts() { @@ -77,17 +78,58 @@ detailsView.bind(viewModel: .init( // .init(title: "Created", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) // ])) -let referendumDAppView = ReferendumDAppView() -view.addSubview(referendumDAppView) -referendumDAppView.snp.makeConstraints { +// let referendumDAppView = ReferendumDAppView() +// view.addSubview(referendumDAppView) +// referendumDAppView.snp.makeConstraints { +// $0.centerY.equalToSuperview() +// $0.leading.trailing.equalToSuperview() +// } +// +// let iconUrl = URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/chains/white/Polkadot.svg")! +// referendumDAppView.bind(viewModel: .init( +// icon: RemoteImageViewModel(url: iconUrl), +// title: "Polkassembly", +// subtitle: "Comment and react" +// )) + +let referendumDetailsTitleView = ReferendumDetailsTitleView() +view.addSubview(referendumDetailsTitleView) +referendumDetailsTitleView.snp.makeConstraints { $0.centerY.equalToSuperview() $0.leading.trailing.equalToSuperview() } -let iconUrl = URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/chains/white/Polkadot.svg")! -referendumDAppView.bind(viewModel: .init( - icon: RemoteImageViewModel(url: iconUrl), - title: "Polkassembly", - subtitle: "Comment and react" -)) +referendumDetailsTitleView.backgroundColor = .darkGray + +func generateMetaAccount(with chainAccounts: Set = []) -> MetaAccountModel { + MetaAccountModel( + metaId: UUID().uuidString, + name: UUID().uuidString, + substrateAccountId: Data.random(of: 32)!, + substrateCryptoType: 0, + substratePublicKey: Data.random(of: 32)!, + ethereumAddress: Data.random(of: 20)!, + ethereumPublicKey: Data.random(of: 32)!, + chainAccounts: chainAccounts, + type: .secrets + ) +} + +let wallet = generateMetaAccount() +let optIcon = wallet.walletIdenticonData().flatMap { try? PolkadotIconGenerator().generateFromAccountId($0) } +let iconViewModel = optIcon.map { DrawableIconViewModel(icon: $0) } + +referendumDetailsTitleView.bind(viewModel: + .init( + track: .init( + titleIcon: .init(title: "main agenda", icon: nil), + referendumNumber: "224" + ), + accountIcon: iconViewModel, + accountName: "RTTI-5220", + title: "Polkadot and Kusama participation in the 10th Pais Digital Chile Summit.", + description: "The Sovereign Nature Initiative transfers, Governance, Sovereign Nature Initiative (SNI) is a non-profit foundation that has" + + "brought together multiple partners and engineers from the лоалыво одыо лоаыдвлоадо", + buttonText: "Read more >" + )) PlaygroundPage.current.liveView = view diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index 7804879218..6ee0d9512d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -15,12 +15,12 @@ final class ReferendumDetailsTitleView: UIView { $0.backgroundView.apply(style: .referendum) $0.titleLabel.numberOfLines = 1 } - + let addressView = PolkadotIconDetailsView() let infoImageView = UIImageView() let textView = UITextView() let moreButton = UIButton() - + override init(frame: CGRect) { super.init(frame: frame) @@ -42,14 +42,16 @@ final class ReferendumDetailsTitleView: UIView { UIView(), trackNameView, numberLabel - ]), + ] + ), UIView.hStack( spacing: 6, [ addressView, infoImageView, UIView() - ]), + ] + ), textView, moreButton ] @@ -69,35 +71,39 @@ extension ReferendumDetailsTitleView { let title: String let description: String let buttonText: String - + struct Track { let titleIcon: TitleIconViewModel let referendumNumber: String? } } - + func bind(viewModel: Model) { numberLabel.isHidden = viewModel.track?.referendumNumber == nil trackNameView.iconDetailsView.bind(viewModel: viewModel.track?.titleIcon) numberLabel.titleLabel.text = viewModel.track?.referendumNumber - + viewModel.accountIcon.map { addressView.imageView.fillColor = $0.fillColor addressView.imageView.bind(icon: $0.icon) } addressView.titleLabel.text = viewModel.accountName - - let titleAttributedString = NSAttributedString(string: viewModel.title, - attributes: titleAttributes) - let descriptionAttributedString = NSAttributedString(string: viewModel.description, - attributes: descriptionAttributes) + + let titleAttributedString = NSAttributedString( + string: viewModel.title, + attributes: titleAttributes + ) + let descriptionAttributedString = NSAttributedString( + string: viewModel.description, + attributes: descriptionAttributes + ) let referndumInfo = NSMutableAttributedString() referndumInfo.append(titleAttributedString) referndumInfo.append(descriptionAttributedString) textView.attributedText = referndumInfo moreButton.setTitle(viewModel.buttonText, for: .normal) } - + private var titleAttributes: [NSAttributedString.Key: Any] { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .byWordWrapping @@ -107,7 +113,7 @@ extension ReferendumDetailsTitleView { .paragraphStyle: paragraphStyle ] } - + private var descriptionAttributes: [NSAttributedString.Key: Any] { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .byWordWrapping @@ -117,5 +123,4 @@ extension ReferendumDetailsTitleView { .paragraphStyle: paragraphStyle ] } - } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 8f3ed3e368..e7a37112b7 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -155,7 +155,18 @@ final class ReferendumsPresenter { } } -extension ReferendumsPresenter: ReferendumsPresenterProtocol {} +extension ReferendumsPresenter: ReferendumsPresenterProtocol { + func selectReferendum(referendumIndex: UInt) { + guard let referendum = referendums?.first(where: { $0.index == referendumIndex }) else { + return + } + wireframe.showReferendumDetails( + from: view, + referendum: referendum, + state: interactor.governanceState + ) + } +} extension ReferendumsPresenter: VoteChildPresenterProtocol { func setup() { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 61621d5866..8d44b2847b 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -8,7 +8,9 @@ protocol ReferendumsViewProtocol: ControllerBackedProtocol { func updateReferendums(time: [UInt: StatusTimeModel?]) } -protocol ReferendumsPresenterProtocol: AnyObject {} +protocol ReferendumsPresenterProtocol: AnyObject { + func selectReferendum(referendumIndex: UInt) +} protocol ReferendumsInteractorInputProtocol: AnyObject { func setup() @@ -18,6 +20,7 @@ protocol ReferendumsInteractorInputProtocol: AnyObject { func refresh() func remakeSubscriptions() func retryBlockTime() + var governanceState: GovernanceSharedState { get } } protocol ReferendumsInteractorOutputProtocol: AnyObject { @@ -38,4 +41,9 @@ protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, Commo delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId? ) + func showReferendumDetails( + from view: ControllerBackedProtocol?, + referendum: ReferendumLocal, + state: GovernanceSharedState + ) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 1a738cf69a..08c805354b 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -54,6 +54,10 @@ extension ReferendumsViewManager: UITableViewDataSource { extension ReferendumsViewManager: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) + switch model.sections[indexPath.section] { + case let .active(_, cells), let .completed(_, cells): + presenter?.selectReferendum(referendumIndex: cells[indexPath.row].referendumIndex) + } } func tableView(_: UITableView, viewForHeaderInSection section: Int) -> UIView? { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index fe82efdb1a..869de1d288 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -24,4 +24,22 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { view?.controller.present(navigationController, animated: true, completion: nil) } + + func showReferendumDetails( + from view: ControllerBackedProtocol?, + referendum: ReferendumLocal, + state: GovernanceSharedState + ) { + guard let referendumDetails = ReferendumDetailsViewFactory.createView( + for: referendum, + state: state + ) else { + return + } + let navigationController = FearlessNavigationController( + rootViewController: referendumDetails.controller + ) + + view?.controller.present(navigationController, animated: true, completion: nil) + } } diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift index ec7bd386fa..afff1b1cd4 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -156,14 +156,13 @@ private extension UILabel.Style { textColor: .white, font: .regularSubheadline ) - } extension UILabel.Style { - static let track = UILabel.Style( - textColor: R.color.colorWhite64(), - font: .semiBoldCaps1 - ) + static let track = UILabel.Style( + textColor: R.color.colorWhite64(), + font: .semiBoldCaps1 + ) } extension RoundedView.Style { From 3890e6365b2c1f4c30c86de0a36f97da6d3ffc64 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 18 Oct 2022 18:19:10 +0500 Subject: [PATCH 056/229] add referendum vote setup interactor --- novawallet.xcodeproj/project.pbxproj | 64 +++++ .../ConvictionVoting+Call.swift | 18 ++ .../ConvictionVoting+ConstantPath.swift | 7 + .../ConvictionVoting/ConvictionVoting.swift | 71 +++++- .../Model/GovernanceLockState.swift | 13 + .../Model/ReferendumAccountVoteLocal.swift | 13 + .../Governance/Model/ReferendumNewVote.swift | 6 + .../Model/ReferendumVoteAction.swift | 8 + .../Operation/Gov2ExtrinsicFactory.swift | 24 ++ .../Operation/Gov2LockStateFactory.swift | 240 ++++++++++++++++++ .../GovernanceExtrinsicFactoryProtocol.swift | 10 + .../GovernanceOperationProtocols.swift | 10 + .../ReferendumVoteInteractor.swift | 175 +++++++++++++ .../ReferendumVoteInteractorError.swift | 8 + .../ReferendumVoteProtocols.swift | 16 ++ .../ReferendumVoteSetupInteractorError.swift | 8 + .../ReferendumVoteSetupInteractor.swift | 198 ++++++++++++++- .../ReferendumVoteSetupPresenter.swift | 25 +- .../ReferendumVoteSetupProtocols.swift | 21 +- .../ReferendumVoteSetupViewFactory.swift | 69 ++++- .../Referendums/ReferendumsInteractor.swift | 1 - 21 files changed, 991 insertions(+), 14 deletions(-) create mode 100644 novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+Call.swift create mode 100644 novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+ConstantPath.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/GovernanceLockState.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumNewVote.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumVoteAction.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/GovernanceExtrinsicFactoryProtocol.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractorError.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumVoteSetupInteractorError.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 06872f6ecc..ea1c16c1b2 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -508,6 +508,14 @@ 84243095265B1888003E07EC /* CrowdloanMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84243094265B1888003E07EC /* CrowdloanMetadata.swift */; }; 8424A8C7262EC0E50091BFB1 /* PayoutInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8424A8C6262EC0E50091BFB1 /* PayoutInfo.swift */; }; 8424DB0B26B8466A008C834F /* ValidatorOperationFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8424DB0A26B8466A008C834F /* ValidatorOperationFactoryProtocol.swift */; }; + 8425D0E028FE738D003B782A /* ReferendumVoteSetupInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425D0DF28FE738D003B782A /* ReferendumVoteSetupInteractorError.swift */; }; + 8425D0E328FE766B003B782A /* ReferendumVoteProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425D0E228FE766B003B782A /* ReferendumVoteProtocols.swift */; }; + 8425D0E628FE82CB003B782A /* ReferendumVoteInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425D0E528FE82CB003B782A /* ReferendumVoteInteractor.swift */; }; + 8425D0E828FE8356003B782A /* ReferendumVoteInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425D0E728FE8356003B782A /* ReferendumVoteInteractorError.swift */; }; + 8425D0EA28FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */; }; + 8425D0EC28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425D0EB28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift */; }; + 8425D0EE28FE9BF1003B782A /* ReferendumVoteAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425D0ED28FE9BF1003B782A /* ReferendumVoteAction.swift */; }; + 8425D0F028FE9CF0003B782A /* ConvictionVoting+Call.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425D0EF28FE9CF0003B782A /* ConvictionVoting+Call.swift */; }; 8425EA8B25EA7AF200C307C9 /* UnappliedSlashes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425EA8A25EA7AF200C307C9 /* UnappliedSlashes.swift */; }; 8425EA9025EA7E5800C307C9 /* ElectedValidatorInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425EA8F25EA7E5800C307C9 /* ElectedValidatorInfo.swift */; }; 8425EA9525EA82CE00C307C9 /* AccountIdentity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8425EA9425EA82CE00C307C9 /* AccountIdentity.swift */; }; @@ -519,6 +527,10 @@ 84264EE1285B6C6700BF6D4A /* XcmTransfersSyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84264EE0285B6C6700BF6D4A /* XcmTransfersSyncTests.swift */; }; 84265E042523D20A005EEE2D /* WalletBaseAmountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E032523D20A005EEE2D /* WalletBaseAmountView.swift */; }; 84265E062523D7BE005EEE2D /* WalletInputAmountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E052523D7BE005EEE2D /* WalletInputAmountView.swift */; }; + 8427495128FEB6E500B2B70B /* GovernanceLockState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8427495028FEB6E500B2B70B /* GovernanceLockState.swift */; }; + 8427495328FEB8C800B2B70B /* ReferendumNewVote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8427495228FEB8C800B2B70B /* ReferendumNewVote.swift */; }; + 8427495528FEB92700B2B70B /* Gov2LockStateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8427495428FEB92700B2B70B /* Gov2LockStateFactory.swift */; }; + 8427495728FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8427495628FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift */; }; 84274B8127A19AFF00A26657 /* OrmlTokenTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84274B8027A19AFF00A26657 /* OrmlTokenTransfer.swift */; }; 842806F32847A51400702F3A /* AccountDetailsSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842806F22847A51400702F3A /* AccountDetailsSelectionView.swift */; }; 842806F52847A82500702F3A /* StackAccountSelectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842806F42847A82500702F3A /* StackAccountSelectionCell.swift */; }; @@ -3361,6 +3373,14 @@ 84243094265B1888003E07EC /* CrowdloanMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanMetadata.swift; sourceTree = ""; }; 8424A8C6262EC0E50091BFB1 /* PayoutInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayoutInfo.swift; sourceTree = ""; }; 8424DB0A26B8466A008C834F /* ValidatorOperationFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorOperationFactoryProtocol.swift; sourceTree = ""; }; + 8425D0DF28FE738D003B782A /* ReferendumVoteSetupInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupInteractorError.swift; sourceTree = ""; }; + 8425D0E228FE766B003B782A /* ReferendumVoteProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteProtocols.swift; sourceTree = ""; }; + 8425D0E528FE82CB003B782A /* ReferendumVoteInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteInteractor.swift; sourceTree = ""; }; + 8425D0E728FE8356003B782A /* ReferendumVoteInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteInteractorError.swift; sourceTree = ""; }; + 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceExtrinsicFactoryProtocol.swift; sourceTree = ""; }; + 8425D0EB28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2ExtrinsicFactory.swift; sourceTree = ""; }; + 8425D0ED28FE9BF1003B782A /* ReferendumVoteAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteAction.swift; sourceTree = ""; }; + 8425D0EF28FE9CF0003B782A /* ConvictionVoting+Call.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConvictionVoting+Call.swift"; sourceTree = ""; }; 8425EA8A25EA7AF200C307C9 /* UnappliedSlashes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnappliedSlashes.swift; sourceTree = ""; }; 8425EA8F25EA7E5800C307C9 /* ElectedValidatorInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElectedValidatorInfo.swift; sourceTree = ""; }; 8425EA9425EA82CE00C307C9 /* AccountIdentity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountIdentity.swift; sourceTree = ""; }; @@ -3372,6 +3392,10 @@ 84264EE0285B6C6700BF6D4A /* XcmTransfersSyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcmTransfersSyncTests.swift; sourceTree = ""; }; 84265E032523D20A005EEE2D /* WalletBaseAmountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletBaseAmountView.swift; sourceTree = ""; }; 84265E052523D7BE005EEE2D /* WalletInputAmountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInputAmountView.swift; sourceTree = ""; }; + 8427495028FEB6E500B2B70B /* GovernanceLockState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceLockState.swift; sourceTree = ""; }; + 8427495228FEB8C800B2B70B /* ReferendumNewVote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumNewVote.swift; sourceTree = ""; }; + 8427495428FEB92700B2B70B /* Gov2LockStateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2LockStateFactory.swift; sourceTree = ""; }; + 8427495628FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConvictionVoting+ConstantPath.swift"; sourceTree = ""; }; 84274B8027A19AFF00A26657 /* OrmlTokenTransfer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrmlTokenTransfer.swift; sourceTree = ""; }; 842806F22847A51400702F3A /* AccountDetailsSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDetailsSelectionView.swift; sourceTree = ""; }; 842806F42847A82500702F3A /* StackAccountSelectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackAccountSelectionCell.swift; sourceTree = ""; }; @@ -6827,6 +6851,24 @@ path = ConnectionPool; sourceTree = ""; }; + 8425D0DE28FE736F003B782A /* Model */ = { + isa = PBXGroup; + children = ( + 8425D0DF28FE738D003B782A /* ReferendumVoteSetupInteractorError.swift */, + ); + path = Model; + sourceTree = ""; + }; + 8425D0E128FE75EA003B782A /* ReferendumVote */ = { + isa = PBXGroup; + children = ( + 8425D0E228FE766B003B782A /* ReferendumVoteProtocols.swift */, + 8425D0E528FE82CB003B782A /* ReferendumVoteInteractor.swift */, + 8425D0E728FE8356003B782A /* ReferendumVoteInteractorError.swift */, + ); + path = ReferendumVote; + sourceTree = ""; + }; 8428228B289B2D2D00163031 /* Base */ = { isa = PBXGroup; children = ( @@ -8495,6 +8537,7 @@ B4F0332763AFF64A3793C679 /* ReferendumDetails */, 872D923BC3CE0F69157DB2EA /* ReferendumFullDetails */, 357F2FABE25DB08B50B329CF /* ReferendumVoters */, + 8425D0E128FE75EA003B782A /* ReferendumVote */, CEE6BB9D4D5A0E46E857EED4 /* ReferendumVoteSetup */, ); path = Governance; @@ -8702,6 +8745,8 @@ 84532D5C28E41D8500EF4ADC /* ConvictionVoting+StoragePath.swift */, 84532D6028E4234700EF4ADC /* ConvictionVotingForKey.swift */, 8448148028E46881007F64FF /* ConvictionVotingLocks.swift */, + 8425D0EF28FE9CF0003B782A /* ConvictionVoting+Call.swift */, + 8427495628FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift */, ); path = ConvictionVoting; sourceTree = ""; @@ -10017,6 +10062,9 @@ 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */, + 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */, + 8425D0EB28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift */, + 8427495428FEB92700B2B70B /* Gov2LockStateFactory.swift */, ); path = Operation; sourceTree = ""; @@ -11263,6 +11311,9 @@ 841221A528F13BA100715C82 /* GovernanceServiceFactory.swift */, 849707A028F3E0AC00DD0A02 /* ReferendumVoterLocal.swift */, 845B811C28F44A700040CE84 /* ReferendumActionLocal.swift */, + 8425D0ED28FE9BF1003B782A /* ReferendumVoteAction.swift */, + 8427495028FEB6E500B2B70B /* GovernanceLockState.swift */, + 8427495228FEB8C800B2B70B /* ReferendumNewVote.swift */, ); path = Model; sourceTree = ""; @@ -12893,6 +12944,7 @@ CEE6BB9D4D5A0E46E857EED4 /* ReferendumVoteSetup */ = { isa = PBXGroup; children = ( + 8425D0DE28FE736F003B782A /* Model */, 5159EA2661A6CBE123CCF891 /* ReferendumVoteSetupProtocols.swift */, 55B2C456A80FA66E6F140814 /* ReferendumVoteSetupWireframe.swift */, 5C6CCACED8D5AFA6543845B7 /* ReferendumVoteSetupPresenter.swift */, @@ -14077,6 +14129,7 @@ F4C2009C2727ED1C00B0F3D0 /* SystemRemarkCall.swift in Sources */, AEF505102616769F0098574D /* InitiatedBonding.swift in Sources */, 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */, + 8425D0E328FE766B003B782A /* ReferendumVoteProtocols.swift in Sources */, F462B364260C88050005AB01 /* UITableView+Reuse.swift in Sources */, 84AE7AA527D35A9800495267 /* StackTableView.swift in Sources */, 88AA0FB828B60E6A00931800 /* YourWalletsControlView.swift in Sources */, @@ -14707,6 +14760,7 @@ 84873B0426029B75000A83EE /* StakingEstimationViewModel.swift in Sources */, AE6F7FE32685E812002BBC3E /* ValidatorListFilterViewLayout.swift in Sources */, 847A6C0928817DC700477F77 /* AssetListBaseInteractorProtocol.swift in Sources */, + 8425D0EA28FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift in Sources */, 84E25BEE27E8895400290BF1 /* TransferErrorPresentable.swift in Sources */, 84038FF026FFBE0600C73F3F /* JsonLocalStorageSubscriber.swift in Sources */, 84BEE0F02562897100D05EB3 /* AccountImportJsonFactory.swift in Sources */, @@ -14745,6 +14799,7 @@ 848E6BDB2761E0E100C91022 /* StakingRewardViewModel.swift in Sources */, 84333BDB285772F300C76A4F /* UInt64+TimeInterval.swift in Sources */, 847999AD2888646000D1BAD2 /* WatchOnlyWalletOperationFactory.swift in Sources */, + 8427495128FEB6E500B2B70B /* GovernanceLockState.swift in Sources */, 8472C5B4265CF9C500E2481B /* StakingRewardDestConfirmPresenter.swift in Sources */, 880059DC28EF092F00E87B9B /* SegmentedSliderView.swift in Sources */, 8402CC9C275B92AC00E5BF30 /* ControlView.swift in Sources */, @@ -15249,6 +15304,7 @@ 846FB02C28C74F9700CA5444 /* ParaStkYieldBoostState.swift in Sources */, 844B2E7C27C426A7000CC079 /* NftLocalSubscriptionHandler.swift in Sources */, 8487584B27F1834E00495306 /* ImageGalleryPresentable.swift in Sources */, + 8427495328FEB8C800B2B70B /* ReferendumNewVote.swift in Sources */, AE20602C2636EA5800357578 /* MoonPayKeys.swift in Sources */, 840B3D70289A575A00DA1DA9 /* ParitySignerScanProtocols.swift in Sources */, 8452585327ABCA07004F9082 /* HideZeroBalancesChanged.swift in Sources */, @@ -15339,6 +15395,7 @@ 84D6D7F627A7D3060094FC33 /* AssetListTotalBalanceCell.swift in Sources */, 849976CC27B3905E00B14A6C /* DAppMetamaskDeniedState.swift in Sources */, 849976B327B2430300B14A6C /* DAppMetamaskTransport.swift in Sources */, + 8425D0EC28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift in Sources */, 84E1CCFA260DCBF9001E81B5 /* SwitchAccount+UsernameSetupWireframe.swift in Sources */, 8473F4BA282C012B007CC55A /* StakingRelaychainInteractor+InputProtocol.swift in Sources */, 848DAEFE282293DB00D56F55 /* ParachainStaking+Types.swift in Sources */, @@ -15398,6 +15455,7 @@ 8442002928E7004B00C49C4A /* VoteViewLayout.swift in Sources */, 84DD5F21263CB6BE00425ACF /* UnbondCall.swift in Sources */, AEF50716262359DC0098574D /* WalletSelectPurchaseProviderCommand.swift in Sources */, + 8425D0E828FE8356003B782A /* ReferendumVoteInteractorError.swift in Sources */, 2AF8204F274FD2120092E3E7 /* BaseAccountCreatePresenter.swift in Sources */, 84282294289BB79300163031 /* ParitySignerSigningWrapper.swift in Sources */, 848DE76226D62AFE0045CD29 /* PersistentStoreCoordinator+Extensions.swift in Sources */, @@ -15445,6 +15503,7 @@ 84EBC55224F660A700459D15 /* EventProtocols.swift in Sources */, AE6F7FE02685E812002BBC3E /* ValidatorListFilterProtocols.swift in Sources */, 84C6801624D7036B00006BF5 /* SubtitleActionControl.swift in Sources */, + 8425D0F028FE9CF0003B782A /* ConvictionVoting+Call.swift in Sources */, 8461CC8726BC1F1F007460E4 /* ExtrinsicOperationFactory.swift in Sources */, 2A028D2A275688E80061CB4C /* AddChainAccount+AccountCreatePresenter.swift in Sources */, 84EFB78928AB7654003B8396 /* LedgerError.swift in Sources */, @@ -15728,6 +15787,7 @@ 8487583227F06AF300495306 /* AddressScanViewFactory.swift in Sources */, 849632072555CE9D00B8E316 /* ExportSeedData.swift in Sources */, 8485D924277E16C400767243 /* DAppBrowserScriptHandler.swift in Sources */, + 8427495528FEB92700B2B70B /* Gov2LockStateFactory.swift in Sources */, 842BDB2C278C4FFE00AB4B5A /* DAppBrowserAuthorizedState.swift in Sources */, 848919DB26FB663D004DBAD5 /* CrowdloansChainViewModel.swift in Sources */, 842A736D27DB7B5E006EE1EA /* OperationTransferViewModel.swift in Sources */, @@ -15896,6 +15956,7 @@ 2C3124A5EBC1AD57C01EEA17 /* SelectValidatorsStartInteractor.swift in Sources */, 88A5318028B9328E00AF18F5 /* YourWalletsViewSectionModel.swift in Sources */, 842EBB312890A76A00B952D8 /* WalletSelectionViewController.swift in Sources */, + 8427495728FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift in Sources */, 84C5ADDF28133F3E006D7388 /* UnknownAddressView.swift in Sources */, 84F6B6502619E1ED0038F10D /* Int+Operations.swift in Sources */, 85547F698B551ACD387D84E2 /* SelectValidatorsStartViewController.swift in Sources */, @@ -16233,6 +16294,7 @@ 5E621A350A6DDD78597CC9E5 /* CrowdloanYourContributionsWireframe.swift in Sources */, 716F0819BAB14322E34E416C /* CrowdloanYourContributionsPresenter.swift in Sources */, F0675F495766D07473B065F7 /* CrowdloanYourContributionsInteractor.swift in Sources */, + 8425D0EE28FE9BF1003B782A /* ReferendumVoteAction.swift in Sources */, 6857DAF09C8D7D5F9C5A5000 /* CrowdloanYourContributionsViewController.swift in Sources */, 487A912B697604FE3367FAEC /* CrowdloanYourContributionsViewLayout.swift in Sources */, 3F7F10D0E1BDE09CBE64BD2D /* CrowdloanYourContributionsViewFactory.swift in Sources */, @@ -16441,6 +16503,7 @@ 688F73AFD5FF20F77242B57E /* ParaStkCollatorsSearchViewController.swift in Sources */, 3BFD635E852E4D395025BEE8 /* ParaStkCollatorsSearchViewFactory.swift in Sources */, 846AACED28BF94B9009F3D42 /* AccountManagementFilter.swift in Sources */, + 8425D0E628FE82CB003B782A /* ReferendumVoteInteractor.swift in Sources */, 766FE2FAB8509BF0F56EA3C0 /* ParaStkCollatorInfoProtocols.swift in Sources */, 4097A50CF5E5794092354758 /* ParaStkCollatorInfoWireframe.swift in Sources */, A8115BE0BFA6558B46CEA101 /* ParaStkCollatorInfoPresenter.swift in Sources */, @@ -16536,6 +16599,7 @@ 012AE9F8BDA682C691B6F9FD /* ParitySignerWelcomeViewController.swift in Sources */, DC2867A7DC1415052D090C53 /* ParitySignerWelcomeViewLayout.swift in Sources */, 97608590E8D770A86CCFBE86 /* ParitySignerWelcomeViewFactory.swift in Sources */, + 8425D0E028FE738D003B782A /* ReferendumVoteSetupInteractorError.swift in Sources */, 5443122935BBFDD55AE9E6FD /* ParitySignerAddressesProtocols.swift in Sources */, 6A2B6DF2D6AE912D5FA62D94 /* ParitySignerAddressesWireframe.swift in Sources */, 65083CD11AE1998A1F4D98F1 /* ParitySignerAddressesPresenter.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+Call.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+Call.swift new file mode 100644 index 0000000000..0b2dfa47ab --- /dev/null +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+Call.swift @@ -0,0 +1,18 @@ +import Foundation +import SubstrateSdk + +extension ConvictionVoting { + struct VoteCall: Codable { + enum CodingKeys: String, CodingKey { + case referendumIndex = "poll_index" + case vote + } + + @StringCodable var referendumIndex: Referenda.ReferendumIndex + let vote: ConvictionVoting.AccountVote + + var runtimeCall: RuntimeCall { + RuntimeCall(moduleName: "ConvictionVoting", callName: "vote", args: self) + } + } +} diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+ConstantPath.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+ConstantPath.swift new file mode 100644 index 0000000000..39c6db75db --- /dev/null +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+ConstantPath.swift @@ -0,0 +1,7 @@ +import Foundation + +extension ConvictionVoting { + static var voteLockingPeriodPath: ConstantCodingPath { + ConstantCodingPath(moduleName: "ConvictionVoting", constantName: "VoteLockingPeriod") + } +} diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index 4c9b0a4639..bc36cd8dfc 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -44,6 +44,27 @@ enum ConvictionVoting { } } + func conviction(for period: Moment) -> Moment? { + switch self { + case .none: + return 0 + case .locked1x: + return period + case .locked2x: + return 2 * period + case .locked3x: + return 4 * period + case .locked4x: + return 8 * period + case .locked5x: + return 16 * period + case .locked6x: + return 32 * period + case .unknown: + return nil + } + } + var decimalValue: Decimal? { switch self { case .none: @@ -66,13 +87,18 @@ enum ConvictionVoting { } } - struct Vote: Decodable { + struct Vote: Codable { static let ayeMask: UInt8 = 1 << 7 static var voteMask: UInt8 { ~ayeMask } let aye: Bool let conviction: Conviction + init(aye: Bool, conviction: Conviction) { + self.aye = aye + self.conviction = conviction + } + public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let compactVote = try container.decode(StringScaleMapper.self).value @@ -82,19 +108,31 @@ enum ConvictionVoting { conviction = Conviction(rawValue: rawConviction) ?? .unknown } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + + let rawConviction = conviction.rawValue + let compactVote = aye ? Self.ayeMask | rawConviction : rawConviction + + try container.encode(StringScaleMapper(value: compactVote)) + } } - struct AccountVoteStandard: Decodable { + struct AccountVoteStandard: Codable { let vote: Vote @StringCodable var balance: BigUInt } - struct AccountVoteSplit: Decodable { + struct AccountVoteSplit: Codable { @StringCodable var aye: BigUInt @StringCodable var nay: BigUInt } - enum AccountVote: Decodable { + enum AccountVote: Codable { + static let standardField = "Standard" + static let splitField = "Split" + case unknown /// A standard vote, one-way (approve or reject) with a given amount of conviction. @@ -111,16 +149,37 @@ enum ConvictionVoting { let type = try container.decode(String.self) switch type { - case "Standard": + case Self.standardField: let vote = try container.decode(AccountVoteStandard.self) self = .standard(vote) - case "Split": + case Self.splitField: let vote = try container.decode(AccountVoteSplit.self) self = .split(vote) default: self = .unknown } } + + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + + switch self { + case let .standard(model): + try container.encode(Self.standardField) + try container.encode(model) + case let .split(model): + try container.encode(Self.splitField) + try container.encode(model) + case .unknown: + throw EncodingError.invalidValue( + self, + .init( + codingPath: container.codingPath, + debugDescription: "Account vote type is unknown" + ) + ) + } + } } struct Delegations: Decodable { diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceLockState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceLockState.swift new file mode 100644 index 0000000000..4b0cd10463 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceLockState.swift @@ -0,0 +1,13 @@ +import Foundation +import BigInt + +struct GovernanceLockState { + let maxLockedAmount: BigUInt + let lockedUntil: BlockNumber? +} + +struct GovernanceLockStateDiff { + let before: GovernanceLockState + let vote: ReferendumNewVote? + let after: GovernanceLockState? +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift index e4bce153cd..df1783c142 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift @@ -58,6 +58,10 @@ enum ReferendumAccountVoteLocal { } } + var totalBalance: BigUInt { + ayeBalance + nayBalance + } + var conviction: Decimal? { switch self { case .split: @@ -67,6 +71,15 @@ enum ReferendumAccountVoteLocal { } } + var convictionValue: ConvictionVoting.Conviction { + switch self { + case .split: + return .locked1x + case let .standard(voting): + return voting.vote.conviction + } + } + init?(accountVote: ConvictionVoting.AccountVote) { switch accountVote { case let .split(split): diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumNewVote.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumNewVote.swift new file mode 100644 index 0000000000..913685fddf --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumNewVote.swift @@ -0,0 +1,6 @@ +import Foundation + +struct ReferendumNewVote { + let index: ReferendumIdLocal + let voteAction: ReferendumVoteAction +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumVoteAction.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumVoteAction.swift new file mode 100644 index 0000000000..16f12f23e1 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumVoteAction.swift @@ -0,0 +1,8 @@ +import Foundation +import BigInt + +struct ReferendumVoteAction: Hashable { + let amount: BigUInt + let conviction: ConvictionVoting.Conviction + let isAye: Bool +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift new file mode 100644 index 0000000000..f52fa96745 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift @@ -0,0 +1,24 @@ +import Foundation +import SubstrateSdk + +final class Gov2ExtrinsicFactory: GovernanceExtrinsicFactoryProtocol { + func vote( + _ action: ReferendumVoteAction, + referendum: ReferendumIdLocal, + builder: ExtrinsicBuilderProtocol + ) throws -> ExtrinsicBuilderProtocol { + let accountVote = ConvictionVoting.AccountVote.standard( + .init( + vote: .init(aye: action.isAye, conviction: action.conviction), + balance: action.amount + ) + ) + + let voteCall = ConvictionVoting.VoteCall( + referendumIndex: Referenda.ReferendumIndex(referendum), + vote: accountVote + ) + + return try builder.adding(call: voteCall.runtimeCall) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift new file mode 100644 index 0000000000..c50be10c0c --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift @@ -0,0 +1,240 @@ +import Foundation +import RobinHood +import SubstrateSdk + +final class Gov2LockStateFactory { + struct AdditionalInfo { + let tracks: [Referenda.TrackId: Referenda.TrackInfo] + let undecidingTimeout: Moment + let voteLockingPeriod: Moment + } + + let requestFactory: StorageRequestFactoryProtocol + + init(requestFactory: StorageRequestFactoryProtocol) { + self.requestFactory = requestFactory + } + + private func createReferendumsWrapper( + for referendumIds: Set, + connection: JSONRPCEngine, + codingFactoryOperation: BaseOperation, + blockHash: Data? + ) -> CompoundOperationWrapper<[ReferendumIdLocal: ReferendumInfo]> { + let remoteIndexes = Array(referendumIds.map { StringScaleMapper(value: $0) }) + + let wrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( + engine: connection, + keyParams: { remoteIndexes }, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: Referenda.referendumInfo, + at: blockHash + ) + + let mappingOperation = ClosureOperation<[ReferendumIdLocal: ReferendumInfo]> { + let responses = try wrapper.targetOperation.extractNoCancellableResultData() + + return zip(remoteIndexes, responses).reduce(into: [ReferendumIdLocal: ReferendumInfo]()) { accum, pair in + accum[pair.0.value] = pair.1.value + } + } + + mappingOperation.addDependency(wrapper.targetOperation) + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: wrapper.allOperations) + } + + private func createAdditionalInfoWrapper( + dependingOn codingFactoryOperation: BaseOperation + ) -> CompoundOperationWrapper { + let tracksOperation = StorageConstantOperation<[Referenda.Track]>(path: Referenda.tracks) + + tracksOperation.configurationBlock = { + do { + tracksOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + tracksOperation.result = .failure(error) + } + } + + let undecidingTimeoutOperation = PrimitiveConstantOperation(path: Referenda.undecidingTimeout) + + undecidingTimeoutOperation.configurationBlock = { + do { + undecidingTimeoutOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + undecidingTimeoutOperation.result = .failure(error) + } + } + + let lockingPeriodOperation = PrimitiveConstantOperation(path: ConvictionVoting.voteLockingPeriodPath) + + lockingPeriodOperation.configurationBlock = { + do { + lockingPeriodOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + lockingPeriodOperation.result = .failure(error) + } + } + + let fetchOperations = [tracksOperation, undecidingTimeoutOperation, lockingPeriodOperation] + fetchOperations.forEach { $0.addDependency(codingFactoryOperation) } + + let mappingOperation = ClosureOperation { + let tracks = try tracksOperation.extractNoCancellableResultData().reduce( + into: [Referenda.TrackId: Referenda.TrackInfo]() + ) { $0[$1.trackId] = $1.info } + + let undecidingTimeout = try undecidingTimeoutOperation.extractNoCancellableResultData() + + let lockingPeriod = try lockingPeriodOperation.extractNoCancellableResultData() + + return AdditionalInfo( + tracks: tracks, + undecidingTimeout: undecidingTimeout, + voteLockingPeriod: lockingPeriod + ) + } + + fetchOperations.forEach { mappingOperation.addDependency($0) } + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: fetchOperations) + } + + private func calculateLocking( + for referendumInfo: ReferendumInfo, + conviction: ConvictionVoting.Conviction, + additionalInfo: AdditionalInfo + ) -> BlockNumber? { + guard let convictionPeriod = conviction.conviction(for: additionalInfo.voteLockingPeriod) else { + return nil + } + + switch referendumInfo { + case let .ongoing(ongoingStatus): + guard let track = additionalInfo.tracks[ongoingStatus.track] else { + return nil + } + + if let decidingSince = ongoingStatus.deciding?.since { + return decidingSince + track.decisionPeriod + convictionPeriod + } else { + return ongoingStatus.submitted + additionalInfo.undecidingTimeout + + track.decisionPeriod + convictionPeriod + } + case let .approved(completedStatus): + return completedStatus.since + convictionPeriod + case .unknown, .killed, .timedOut, .cancelled, .rejected: + return nil + } + } + + private func createStateDiffOperation( + for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + newVote: ReferendumNewVote?, + referendumsOperation: BaseOperation<[ReferendumIdLocal: ReferendumInfo]>, + additionalInfoOperation: BaseOperation + ) -> BaseOperation { + ClosureOperation { + let referendums = try referendumsOperation.extractNoCancellableResultData() + let additions = try additionalInfoOperation.extractNoCancellableResultData() + + let oldAmount = votes.values.map(\.totalBalance).max() ?? 0 + + let oldPeriod: Moment? = referendums.compactMap { referendumKeyValue in + let referendumIndex = referendumKeyValue.key + let referendum = referendumKeyValue.value + + guard let vote = votes[referendumIndex], vote.totalBalance > 0 else { + return nil + } + + let conviction = vote.convictionValue + return self.calculateLocking(for: referendum, conviction: conviction, additionalInfo: additions) + }.max() + + let oldState = GovernanceLockState(maxLockedAmount: oldAmount, lockedUntil: oldPeriod) + + let newState: GovernanceLockState? + + if let newVote = newVote { + let filteredVotes = votes.filter { $0.key != newVote.index } + let newAmount = (filteredVotes.values.map(\.totalBalance) + [newVote.voteAction.amount]).max() ?? 0 + + let newPeriod: Moment? = referendums.compactMap { referendumKeyValue in + let referendumIndex = referendumKeyValue.key + let referendum = referendumKeyValue.value + + let conviction: ConvictionVoting.Conviction + + if referendumIndex == newVote.index { + guard newVote.voteAction.amount > 0 else { + return nil + } + + conviction = newVote.voteAction.conviction + } else { + guard let vote = filteredVotes[referendumIndex], vote.totalBalance > 0 else { + return nil + } + + conviction = vote.convictionValue + } + + return self.calculateLocking(for: referendum, conviction: conviction, additionalInfo: additions) + }.max() + + newState = GovernanceLockState(maxLockedAmount: newAmount, lockedUntil: newPeriod) + } else { + newState = nil + } + + return GovernanceLockStateDiff(before: oldState, vote: newVote, after: newState) + } + } +} + +extension Gov2LockStateFactory: GovernanceLockStateFactoryProtocol { + func calculateLockStateDiff( + for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + newVote: ReferendumNewVote?, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + var allReferendumIds = Set(votes.keys) + + if let newVoteIndex = newVote?.index { + allReferendumIds.insert(newVoteIndex) + } + + let referendumsWrapper = createReferendumsWrapper( + for: allReferendumIds, + connection: connection, + codingFactoryOperation: codingFactoryOperation, + blockHash: blockHash + ) + + let additionalInfoWrapper = createAdditionalInfoWrapper(dependingOn: codingFactoryOperation) + + referendumsWrapper.addDependency(operations: [codingFactoryOperation]) + additionalInfoWrapper.addDependency(operations: [codingFactoryOperation]) + + let calculationOperation = createStateDiffOperation( + for: votes, + newVote: newVote, + referendumsOperation: referendumsWrapper.targetOperation, + additionalInfoOperation: additionalInfoWrapper.targetOperation + ) + + calculationOperation.addDependency(referendumsWrapper.targetOperation) + calculationOperation.addDependency(additionalInfoWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + referendumsWrapper.allOperations + + additionalInfoWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: calculationOperation, dependencies: dependencies) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceExtrinsicFactoryProtocol.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceExtrinsicFactoryProtocol.swift new file mode 100644 index 0000000000..c7e8e292c5 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceExtrinsicFactoryProtocol.swift @@ -0,0 +1,10 @@ +import Foundation +import SubstrateSdk + +protocol GovernanceExtrinsicFactoryProtocol { + func vote( + _ vote: ReferendumVoteAction, + referendum: ReferendumIdLocal, + builder: ExtrinsicBuilderProtocol + ) throws -> ExtrinsicBuilderProtocol +} diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift index f2b973c277..792420e4bd 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -29,3 +29,13 @@ protocol ReferendumActionOperationFactoryProtocol { runtimeProvider: RuntimeProviderProtocol ) -> CompoundOperationWrapper } + +protocol GovernanceLockStateFactoryProtocol { + func calculateLockStateDiff( + for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + newVote: ReferendumNewVote?, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift new file mode 100644 index 0000000000..932a376072 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift @@ -0,0 +1,175 @@ +import Foundation +import RobinHood +import BigInt + +class ReferendumVoteInteractor { + private weak var basePresenter: ReferendumVoteInteractorOutputProtocol? + + let referendumIndex: ReferendumIdLocal + let selectedAccount: MetaChainAccountResponse + let chain: ChainModel + let referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol + let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol + let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol + let extrinsicService: ExtrinsicServiceProtocol + let feeProxy: ExtrinsicFeeProxyProtocol + let extrinsicFactory: GovernanceExtrinsicFactoryProtocol + + private var priceProvider: AnySingleValueProvider? + private var assetBalanceProvider: StreamableProvider? + + init( + referendumIndex: ReferendumIdLocal, + selectedAccount: MetaChainAccountResponse, + chain: ChainModel, + referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + extrinsicFactory: GovernanceExtrinsicFactoryProtocol, + extrinsicService: ExtrinsicServiceProtocol, + feeProxy: ExtrinsicFeeProxyProtocol, + currencyManager: CurrencyManagerProtocol + ) { + self.referendumIndex = referendumIndex + self.selectedAccount = selectedAccount + self.chain = chain + self.referendumsSubscriptionFactory = referendumsSubscriptionFactory + self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory + self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory + self.extrinsicFactory = extrinsicFactory + self.extrinsicService = extrinsicService + self.feeProxy = feeProxy + self.currencyManager = currencyManager + } + + deinit { + clearReferendumSubscriptions() + } + + private func clearReferendumSubscriptions() { + referendumsSubscriptionFactory.unsubscribeFromReferendum(self, referendumIndex: referendumIndex) + } + + private func subscribeBalanceIfNeeded() { + assetBalanceProvider?.removeObserver(self) + assetBalanceProvider = nil + + if let asset = chain.utilityAsset() { + assetBalanceProvider = subscribeToAssetBalanceProvider( + for: selectedAccount.chainAccount.accountId, + chainId: chain.chainId, + assetId: asset.assetId + ) + } + } + + private func subscribePriceIfNeeded() { + priceProvider?.removeObserver(self) + priceProvider = nil + + if let priceId = chain.utilityAsset()?.priceId { + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } + } + + private func subscribeReferendum() { + referendumsSubscriptionFactory.subscribeToReferendum(self, referendumIndex: referendumIndex) { [weak self] result in + switch result { + case let .success(storageResult): + if let referendum = storageResult.value { + self?.basePresenter?.didReceiveVotingReferendum(referendum) + } + case let .failure(error): + self?.basePresenter?.didReceiveBaseError(.votingReferendumFailed(error)) + case .none: + break + } + } + } + + private func makeSubscriptions() { + subscribeBalanceIfNeeded() + subscribePriceIfNeeded() + + clearReferendumSubscriptions() + subscribeReferendum() + } + + func setup() { + feeProxy.delegate = self + + makeSubscriptions() + } + + func remakeSubscriptions() { + makeSubscriptions() + } +} + +extension ReferendumVoteInteractor: ReferendumVoteInteractorInputProtocol { + func estimateFee(for vote: ReferendumVoteAction) { + let reuseIdentifier = "\(vote.hashValue)" + + feeProxy.estimateFee(using: extrinsicService, reuseIdentifier: reuseIdentifier) { [weak self] builder in + guard let strongSelf = self else { + return builder + } + + return try strongSelf.extrinsicFactory.vote( + vote, + referendum: strongSelf.referendumIndex, + builder: builder + ) + } + } +} + +extension ReferendumVoteInteractor: WalletLocalSubscriptionHandler, WalletLocalStorageSubscriber { + func handleAssetBalance( + result: Result, + accountId _: AccountId, + chainId _: ChainModel.Id, + assetId _: AssetModel.Id + ) { + switch result { + case let .success(balance): + basePresenter?.didReceiveAssetBalance(balance) + case let .failure(error): + basePresenter?.didReceiveBaseError(.assetBalanceFailed(error)) + } + } +} + +extension ReferendumVoteInteractor: PriceLocalSubscriptionHandler, PriceLocalStorageSubscriber { + func handlePrice(result: Result, priceId _: AssetModel.PriceId) { + switch result { + case let .success(price): + basePresenter?.didReceivePrice(price) + case let .failure(error): + basePresenter?.didReceiveBaseError(.priceFailed(error)) + } + } +} + +extension ReferendumVoteInteractor: ExtrinsicFeeProxyDelegate { + func didReceiveFee(result: Result, for _: ExtrinsicFeeId) { + switch result { + case let .success(dispatchInfo): + if let fee = BigUInt(dispatchInfo.fee) { + basePresenter?.didReceiveFee(fee) + } + case let .failure(error): + basePresenter?.didReceiveBaseError(.feeFailed(error)) + } + } +} + +extension ReferendumVoteInteractor: SelectedCurrencyDepending { + func applyCurrency() { + guard basePresenter != nil else { + return + } + + subscribePriceIfNeeded() + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractorError.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractorError.swift new file mode 100644 index 0000000000..bcfbcbdd4e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractorError.swift @@ -0,0 +1,8 @@ +import Foundation + +enum ReferendumVoteInteractorError: Error { + case assetBalanceFailed(_ internalError: Error) + case priceFailed(_ internalError: Error) + case votingReferendumFailed(_ internalError: Error) + case feeFailed(_ internalError: Error) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift new file mode 100644 index 0000000000..4c0dc61d11 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift @@ -0,0 +1,16 @@ +import Foundation +import BigInt + +protocol ReferendumVoteInteractorInputProtocol: AnyObject { + func setup() + func remakeSubscriptions() + func estimateFee(for vote: ReferendumVoteAction) +} + +protocol ReferendumVoteInteractorOutputProtocol: AnyObject { + func didReceiveAssetBalance(_ balance: AssetBalance?) + func didReceivePrice(_ price: PriceData?) + func didReceiveVotingReferendum(_ referendum: ReferendumLocal) + func didReceiveFee(_ fee: BigUInt) + func didReceiveBaseError(_ error: ReferendumVoteInteractorError) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumVoteSetupInteractorError.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumVoteSetupInteractorError.swift new file mode 100644 index 0000000000..6c705cfc33 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumVoteSetupInteractorError.swift @@ -0,0 +1,8 @@ +import Foundation + +enum ReferendumVoteSetupInteractorError: Error { + case accountVotesFailed(_ internalError: Error) + case blockNumberSubscriptionFailed(_ internalError: Error) + case blockTimeFailed(_ internalError: Error) + case stateDiffFailed(_ internalError: Error) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift index e8aeac2f3d..d2eccf6fee 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift @@ -1,7 +1,201 @@ import UIKit +import SubstrateSdk +import RobinHood -final class ReferendumVoteSetupInteractor { +final class ReferendumVoteSetupInteractor: ReferendumVoteInteractor, AnyCancellableCleaning { weak var presenter: ReferendumVoteSetupInteractorOutputProtocol? + + let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol + let blockTimeService: BlockTimeEstimationServiceProtocol + let lockStateFactory: GovernanceLockStateFactoryProtocol + let connection: JSONRPCEngine + let runtimeProvider: RuntimeProviderProtocol + let operationQueue: OperationQueue + + private var blockNumberSubscription: AnyDataProvider? + + private var blockTimeCancellable: CancellableCall? + private var lockDiffCancellable: CancellableCall? + + init( + referendumIndex: ReferendumIdLocal, + selectedAccount: MetaChainAccountResponse, + chain: ChainModel, + generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, + referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + blockTimeService: BlockTimeEstimationServiceProtocol, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + currencyManager: CurrencyManagerProtocol, + extrinsicFactory: GovernanceExtrinsicFactoryProtocol, + extrinsicService: ExtrinsicServiceProtocol, + feeProxy: ExtrinsicFeeProxyProtocol, + lockStateFactory: GovernanceLockStateFactoryProtocol, + operationQueue: OperationQueue + ) { + self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory + self.blockTimeService = blockTimeService + self.connection = connection + self.runtimeProvider = runtimeProvider + self.lockStateFactory = lockStateFactory + self.operationQueue = operationQueue + + super.init( + referendumIndex: referendumIndex, + selectedAccount: selectedAccount, + chain: chain, + referendumsSubscriptionFactory: referendumsSubscriptionFactory, + walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, + priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, + extrinsicFactory: extrinsicFactory, + extrinsicService: extrinsicService, + feeProxy: feeProxy, + currencyManager: currencyManager + ) + } + + deinit { + clearReferendumSubscriptions() + clearCancellable() + } + + private func clearCancellable() { + clear(cancellable: &blockTimeCancellable) + clear(cancellable: &lockDiffCancellable) + } + + private func provideBlockTime() { + guard blockTimeCancellable == nil else { + return + } + + let operation = blockTimeService.createEstimatedBlockTimeOperation() + + operation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard operation === self?.blockTimeCancellable else { + return + } + + self?.blockTimeCancellable = nil + + do { + let blockTimeModel = try operation.extractNoCancellableResultData() + self?.presenter?.didReceiveBlockTime(blockTimeModel.blockTime) + } catch { + self?.presenter?.didReceiveError(.blockTimeFailed(error)) + } + } + } + + blockTimeCancellable = operation + + operationQueue.addOperation(operation) + } + + private func clearReferendumSubscriptions() { + referendumsSubscriptionFactory.unsubscribeFromAccountVotes( + self, + accountId: selectedAccount.chainAccount.accountId + ) + } + + private func clearAndSubscribeBlockNumber() { + blockNumberSubscription?.removeObserver(self) + blockNumberSubscription = nil + + blockNumberSubscription = subscribeToBlockNumber(for: chain.chainId) + } + + private func subscribeAccountVotes() { + clearReferendumSubscriptions() + + referendumsSubscriptionFactory.subscribeToAccountVotes( + self, + accountId: selectedAccount.chainAccount.accountId + ) { [weak self] result in + switch result { + case let .success(storageResult): + self?.presenter?.didReceiveAccountVotes(storageResult) + case let .failure(error): + self?.presenter?.didReceiveError(.accountVotesFailed(error)) + case .none: + self?.presenter?.didReceiveAccountVotes(.init(value: nil, blockHash: nil)) + } + } + } + + private func makeSubscriptions() { + clearAndSubscribeBlockNumber() + } + + override func setup() { + super.setup() + + makeSubscriptions() + } + + override func remakeSubscriptions() { + super.remakeSubscriptions() + + makeSubscriptions() + } } -extension ReferendumVoteSetupInteractor: ReferendumVoteSetupInteractorInputProtocol {} +extension ReferendumVoteSetupInteractor: ReferendumVoteSetupInteractorInputProtocol { + func refreshLockDiff( + for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + newVote: ReferendumNewVote?, + blockHash: Data? + ) { + clear(cancellable: &lockDiffCancellable) + + let wrapper = lockStateFactory.calculateLockStateDiff( + for: votes, + newVote: newVote, + from: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.lockDiffCancellable else { + return + } + + self?.lockDiffCancellable = nil + + do { + let stateDiff = try wrapper.targetOperation.extractNoCancellableResultData() + self?.presenter?.didReceiveLockStateDiff(stateDiff) + } catch { + self?.presenter?.didReceiveError(.stateDiffFailed(error)) + } + } + } + + lockDiffCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } + + func refreshBlockTime() { + provideBlockTime() + } +} + +extension ReferendumVoteSetupInteractor: GeneralLocalStorageSubscriber, GeneralLocalStorageHandler { + func handleBlockNumber(result: Result, chainId _: ChainModel.Id) { + switch result { + case let .success(blockNumber): + if let blockNumber = blockNumber { + presenter?.didReceiveBlockNumber(blockNumber) + } + case let .failure(error): + presenter?.didReceiveError(.blockNumberSubscriptionFailed(error)) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 732ad4c40b..53009eda2f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -1,4 +1,5 @@ import Foundation +import BigInt final class ReferendumVoteSetupPresenter { weak var view: ReferendumVoteSetupViewProtocol? @@ -18,4 +19,26 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { func setup() {} } -extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProtocol {} +extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProtocol { + func didReceiveLockStateDiff(_: GovernanceLockStateDiff) {} + + func didReceiveAccountVotes( + _: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]> + ) {} + + func didReceiveBlockNumber(_: BlockNumber) {} + + func didReceiveBlockTime(_: BlockTime) {} + + func didReceiveError(_: ReferendumVoteSetupInteractorError) {} + + func didReceiveAssetBalance(_: AssetBalance?) {} + + func didReceivePrice(_: PriceData?) {} + + func didReceiveVotingReferendum(_: ReferendumLocal) {} + + func didReceiveFee(_: BigUInt) {} + + func didReceiveBaseError(_: ReferendumVoteInteractorError) {} +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index 9e168a3567..ab2055d64d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -1,11 +1,28 @@ +import BigInt protocol ReferendumVoteSetupViewProtocol: AnyObject {} protocol ReferendumVoteSetupPresenterProtocol: AnyObject { func setup() } -protocol ReferendumVoteSetupInteractorInputProtocol: AnyObject {} +protocol ReferendumVoteSetupInteractorInputProtocol: ReferendumVoteInteractorInputProtocol { + func refreshLockDiff( + for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + newVote: ReferendumNewVote?, + blockHash: Data? + ) -protocol ReferendumVoteSetupInteractorOutputProtocol: AnyObject {} + func refreshBlockTime() +} + +protocol ReferendumVoteSetupInteractorOutputProtocol: ReferendumVoteInteractorOutputProtocol { + func didReceiveLockStateDiff(_ stateDiff: GovernanceLockStateDiff) + func didReceiveAccountVotes( + _ votes: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]> + ) + func didReceiveBlockNumber(_ number: BlockNumber) + func didReceiveBlockTime(_ blockTime: BlockTime) + func didReceiveError(_ error: ReferendumVoteSetupInteractorError) +} protocol ReferendumVoteSetupWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index 5a532d32e3..43aca0b07b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -1,8 +1,18 @@ import Foundation +import SubstrateSdk +import RobinHood struct ReferendumVoteSetupViewFactory { - static func createView() -> ReferendumVoteSetupViewProtocol? { - let interactor = ReferendumVoteSetupInteractor() + static func createView( + for state: GovernanceSharedState, + referendum: ReferendumIdLocal + ) -> ReferendumVoteSetupViewProtocol? { + guard + let currencyManager = CurrencyManager.shared, + let interactor = createInteractor(for: state, referendum: referendum, currencyManager: currencyManager) else { + return nil + } + let wireframe = ReferendumVoteSetupWireframe() let presenter = ReferendumVoteSetupPresenter(interactor: interactor, wireframe: wireframe) @@ -14,4 +24,59 @@ struct ReferendumVoteSetupViewFactory { return view } + + private static func createInteractor( + for state: GovernanceSharedState, + referendum: ReferendumIdLocal, + currencyManager: CurrencyManagerProtocol + ) -> ReferendumVoteSetupInteractor? { + guard + let chain = state.settings.value, + let selectedAccount = SelectedWalletSettings.shared.value?.fetchMetaChainAccount(for: chain.accountRequest()), + let subscriptionFactory = state.subscriptionFactory, + let blockTimeService = state.blockTimeService + else { + return nil + } + + let chainRegistry = state.chainRegistry + + guard + let connection = chainRegistry.getConnection(for: chain.chainId), + let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + return nil + } + + let operationQueue = OperationManagerFacade.sharedDefaultQueue + let operationManager = OperationManager(operationQueue: operationQueue) + + let requestFactory = StorageRequestFactory(remoteFactory: StorageKeyFactory(), operationManager: operationManager) + + let lockStateFactory = Gov2LockStateFactory(requestFactory: requestFactory) + + let extrinsicService = ExtrinsicServiceFactory( + runtimeRegistry: runtimeProvider, + engine: connection, + operationManager: operationManager + ).createService(account: selectedAccount.chainAccount, chain: chain) + + return ReferendumVoteSetupInteractor( + referendumIndex: referendum, + selectedAccount: selectedAccount, + chain: chain, + generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, + referendumsSubscriptionFactory: subscriptionFactory, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + blockTimeService: blockTimeService, + connection: connection, + runtimeProvider: runtimeProvider, + currencyManager: currencyManager, + extrinsicFactory: Gov2ExtrinsicFactory(), + extrinsicService: extrinsicService, + feeProxy: ExtrinsicFeeProxy(), + lockStateFactory: lockStateFactory, + operationQueue: operationQueue + ) + } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 837631a783..fecfb2737c 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -12,7 +12,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let referendumsOperationFactory: ReferendumsOperationFactoryProtocol - let currencyManager: CurrencyManagerProtocol let applicationHandler: ApplicationHandlerProtocol let serviceFactory: GovernanceServiceFactoryProtocol let operationQueue: OperationQueue From f6a58e730dbda45664723cebcb99a0bbcda985a8 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 18 Oct 2022 18:31:37 +0300 Subject: [PATCH 057/229] fix layout, added rows --- novawallet.xcodeproj/project.pbxproj | 26 ++- .../ReferendumDetailsProtocols.swift | 7 +- .../ReferendumDetailsViewController.swift | 100 +++++++++- .../ReferendumDetailsViewLayout.swift | 58 ++++-- .../ReferendumDetails/View/BlurredView.swift | 62 +++++++ .../MyPlayground.playground/Contents.swift | 135 -------------- .../Resources/PublicSans-Bold.otf | Bin 56032 -> 0 bytes .../Resources/PublicSans-ExtraBold.otf | Bin 56468 -> 0 bytes .../Resources/PublicSans-ExtraLight.otf | Bin 56584 -> 0 bytes .../Resources/PublicSans-Medium.otf | Bin 56180 -> 0 bytes .../Resources/PublicSans-Regular.otf | Bin 56792 -> 0 bytes .../Resources/PublicSans-SemiBold.otf | Bin 56720 -> 0 bytes .../contents.xcplayground | 4 - .../timeline.xctimeline | 6 - .../View/ReferendumDAppView.swift | 2 +- .../View/ReferendumDetailsTitleView.swift | 34 +++- .../View/ReferendumTimelineView.swift | 174 ------------------ .../ReferendumVotingStatusDetailsView.swift | 6 +- .../View/ReferendumVotingStatusView.swift | 2 +- .../View/Timeline/BaselinedView.swift | 17 ++ .../Timeline/ReferendumTimelineView.swift | 86 +++++++++ 21 files changed, 366 insertions(+), 353 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Bold.otf delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraBold.otf delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraLight.otf delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Medium.otf delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Regular.otf delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-SemiBold.otf delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/contents.xcplayground delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/timeline.xctimeline delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/BaselinedView.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 5338f7a02a..718c9ece19 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2234,6 +2234,8 @@ 8860F3E4289D50BA00C0BF86 /* Array+SectionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8860F3E3289D50BA00C0BF86 /* Array+SectionProtocol.swift */; }; 8860F3E8289D7CF400C0BF86 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8860F3E7289D7CF400C0BF86 /* Atomic.swift */; }; 886E8CF81EF2566D98D9693E /* ExportSeedViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FA66143B25AA70B02CE461 /* ExportSeedViewFactory.swift */; }; + 887A717C28FEF03E00B13C7E /* BaselinedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887A717B28FEF03E00B13C7E /* BaselinedView.swift */; }; + 887A717E28FEF10D00B13C7E /* BlurredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887A717D28FEF10D00B13C7E /* BlurredView.swift */; }; 887AFC8728BC95F0002A0422 /* MetaAccountChainResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887AFC8628BC95F0002A0422 /* MetaAccountChainResponse.swift */; }; 887AFC8C28BCB314002A0422 /* PolkadotIconDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887AFC8928BCB313002A0422 /* PolkadotIconDetailsView.swift */; }; 887AFC8D28BCB314002A0422 /* SelectableIconSubtitleCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887AFC8A28BCB313002A0422 /* SelectableIconSubtitleCollectionViewCell.swift */; }; @@ -2266,9 +2268,8 @@ 88AC186528CA461F00892A9B /* ModalSheetCollectionViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AC186428CA461F00892A9B /* ModalSheetCollectionViewProtocol.swift */; }; 88AF35DE28C21D28003730DA /* LocksSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AF35DD28C21D28003730DA /* LocksSubscription.swift */; }; 88B1862A28EF30A600D49854 /* YourVoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B1862928EF30A600D49854 /* YourVoteView.swift */; }; - 88B438E728F6C629001FC08A /* StatusTimeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B438E628F6C629001FC08A /* StatusTimeModel.swift */; }; - 88B560BC28F80DCB00A5EB59 /* VoteRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */; }; 88B438E728F6C629001FC08A /* StatusTimeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B438E628F6C629001FC08A /* StatusTimeViewModel.swift */; }; + 88B560BC28F80DCB00A5EB59 /* VoteRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */; }; 88BB21A028D34C660019C6B4 /* DataProviderChange+Identifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88BB219F28D34C660019C6B4 /* DataProviderChange+Identifier.swift */; }; 88C017E628C60A65003B2D28 /* AssetLockMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C017E528C60A65003B2D28 /* AssetLockMapper.swift */; }; 88C7165428C894510015D1E9 /* CollectionViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C7165328C894510015D1E9 /* CollectionViewDelegate.swift */; }; @@ -5112,6 +5113,8 @@ 8860F3E3289D50BA00C0BF86 /* Array+SectionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+SectionProtocol.swift"; sourceTree = ""; }; 8860F3E7289D7CF400C0BF86 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; 88787F0328DB3A7B00B115AB /* SubstrateDataModel2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SubstrateDataModel2.xcdatamodel; sourceTree = ""; }; + 887A717B28FEF03E00B13C7E /* BaselinedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaselinedView.swift; sourceTree = ""; }; + 887A717D28FEF10D00B13C7E /* BlurredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurredView.swift; sourceTree = ""; }; 887AFC8628BC95F0002A0422 /* MetaAccountChainResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaAccountChainResponse.swift; sourceTree = ""; }; 887AFC8928BCB313002A0422 /* PolkadotIconDetailsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PolkadotIconDetailsView.swift; sourceTree = ""; }; 887AFC8A28BCB313002A0422 /* SelectableIconSubtitleCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectableIconSubtitleCollectionViewCell.swift; sourceTree = ""; }; @@ -5145,10 +5148,8 @@ 88AC186428CA461F00892A9B /* ModalSheetCollectionViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalSheetCollectionViewProtocol.swift; sourceTree = ""; }; 88AF35DD28C21D28003730DA /* LocksSubscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocksSubscription.swift; sourceTree = ""; }; 88B1862928EF30A600D49854 /* YourVoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourVoteView.swift; sourceTree = ""; }; - 88B438E628F6C629001FC08A /* StatusTimeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTimeModel.swift; sourceTree = ""; }; - 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteRowView.swift; sourceTree = ""; }; - 88B560BD28F831CC00A5EB59 /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 88B438E628F6C629001FC08A /* StatusTimeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTimeViewModel.swift; sourceTree = ""; }; + 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoteRowView.swift; sourceTree = ""; }; 88BB219F28D34C660019C6B4 /* DataProviderChange+Identifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataProviderChange+Identifier.swift"; sourceTree = ""; }; 88C017E528C60A65003B2D28 /* AssetLockMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetLockMapper.swift; sourceTree = ""; }; 88C7165328C894510015D1E9 /* CollectionViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewDelegate.swift; sourceTree = ""; }; @@ -12074,6 +12075,15 @@ path = Currency; sourceTree = ""; }; + 887A717A28FEF03000B13C7E /* Timeline */ = { + isa = PBXGroup; + children = ( + 88A95FA528F8664100BE26F3 /* ReferendumTimelineView.swift */, + 887A717B28FEF03E00B13C7E /* BaselinedView.swift */, + ); + path = Timeline; + sourceTree = ""; + }; 887AFC8828BCB313002A0422 /* View */ = { isa = PBXGroup; children = ( @@ -12087,13 +12097,13 @@ 888A3B6328F73B9200E15BD2 /* View */ = { isa = PBXGroup; children = ( - 88A95FA528F8664100BE26F3 /* ReferendumTimelineView.swift */, + 887A717A28FEF03000B13C7E /* Timeline */, 888A3B6628F746D200E15BD2 /* ReferendumVotingStatusDetailsView.swift */, 888A3B6428F73DC300E15BD2 /* ReferendumVotingStatusView.swift */, 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */, 88A95FA728FAA99D00BE26F3 /* ReferendumDAppView.swift */, 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */, - 88B560BD28F831CC00A5EB59 /* MyPlayground.playground */, + 887A717D28FEF10D00B13C7E /* BlurredView.swift */, ); path = View; sourceTree = ""; @@ -14854,6 +14864,7 @@ 84466B4028B77B4500FA1E0D /* SignatureVerificationWrapper.swift in Sources */, 844DBC62274D1E29009F8351 /* SecretTypeTableViewCell.swift in Sources */, 847297A2260B3146009B86D0 /* ChangeTargetsSelectValidatorsStartWireframe.swift in Sources */, + 887A717E28FEF10D00B13C7E /* BlurredView.swift in Sources */, 849D755B2756910A007726C3 /* RoundedView+Style.swift in Sources */, 84038FEC26FFBA4D00C73F3F /* PriceLocalStorageSubscriber.swift in Sources */, 841221A428F0A3F200715C82 /* ReferendumAccountVoteLocal.swift in Sources */, @@ -15140,6 +15151,7 @@ 846AF8402525B94D00868F37 /* WalletNetworkFacade+Protocol.swift in Sources */, F40966FF26B29A58008CD244 /* FWBarChartView.swift in Sources */, 8468B86C24F63CEF00B76BC6 /* AddAccount+AccountConfirmInteractor.swift in Sources */, + 887A717C28FEF03E00B13C7E /* BaselinedView.swift in Sources */, 84BD388D28A25CB800A9918E /* UILabel+ExpirationTimer.swift in Sources */, 841E554D282DAA8000C8438F /* ParachainStakingServiceFactory.swift in Sources */, F43A597B26D53775005E973D /* AnalyticsBaseViewController.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 3209f479fa..11e068f795 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -1,4 +1,9 @@ -protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol {} +protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { + func set(votingDetails: ReferendumVotingStatusDetailsView.Model) + func set(dAppModels: [ReferendumDAppView.Model]) + func set(timelineModel: ReferendumTimelineView.Model) + func set(titleModel: ReferendumDetailsTitleView.Model) +} protocol ReferendumDetailsPresenterProtocol: AnyObject { func setup() diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 4d446f00d5..466480a1f5 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -1,6 +1,7 @@ import UIKit +import SubstrateSdk -final class ReferendumDetailsViewController: UIViewController { +final class ReferendumDetailsViewController: UIViewController, ViewHolder { typealias RootViewType = ReferendumDetailsViewLayout let presenter: ReferendumDetailsPresenterProtocol @@ -23,7 +24,102 @@ final class ReferendumDetailsViewController: UIViewController { super.viewDidLoad() presenter.setup() + setSamples() + } + + private func setSamples() { + let status = ReferendumVotingStatusView.Model( + status: .init(name: "PASSING", kind: .positive), + time: .init(titleIcon: .init(title: "Approve in 03:59:59", icon: R.image.iconFire()), isUrgent: true), + title: "Voting status" + ) + let votingProgress = VotingProgressView.Model( + support: .init(title: "Threshold reached", icon: R.image.iconCheckmark()?.withTintColor(R.color.colorGreen15CF37()!)), + approval: .init( + passThreshold: 0.5, + ayeProgress: 0.9, + ayeMessage: "Aye: 99.9%", + passMessage: "To pass: 50%", + nayMessage: "Nay: 0.1%" + ) + ) + set(votingDetails: .init( + status: status, + votingProgress: votingProgress, + aye: .init( + title: "Aye", + votes: "25,354.16 votes", + tokens: "16,492 KSM" + ), + nay: .init( + title: "Nay", + votes: "1.5 votes", + tokens: "149 KSM" + ), + buttonText: "Vote" + )) + + let iconUrl = URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/chains/white/Polkadot.svg")! + set(dAppModels: [ + .init( + icon: RemoteImageViewModel(url: iconUrl), + title: "Polkassembly", + subtitle: "Comment and react" + ) + ]) + + let metaAccount = MetaAccountModel( + metaId: UUID().uuidString, + name: UUID().uuidString, + substrateAccountId: Data.random(of: 32)!, + substrateCryptoType: 0, + substratePublicKey: Data.random(of: 32)!, + ethereumAddress: Data.random(of: 20)!, + ethereumPublicKey: Data.random(of: 32)!, + chainAccounts: [], + type: .secrets + ) + + let optIcon = metaAccount.walletIdenticonData().flatMap { try? PolkadotIconGenerator().generateFromAccountId($0) } + let iconViewModel = optIcon.map { DrawableIconViewModel(icon: $0) } + + set(titleModel: .init( + track: .init( + titleIcon: .init(title: "main agenda", icon: nil), + referendumNumber: "224" + ), + accountIcon: iconViewModel, + accountName: "RTTI-5220", + title: "Polkadot and Kusama participation in the 10th Pais Digital Chile Summit.", + description: "The Sovereign Nature Initiative transfers, Governance, Sovereign Nature Initiative (SNI) is a non-profit foundation that has" + + "brought together multiple partners and engineers from the лоалыво одыо лоаыдвлоадо", + buttonText: "Read more" + ) + ) + + set(timelineModel: .init(title: "Timeline", statuses: [ + .init(title: "Created", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), + .init(title: "Created", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) + ])) + + rootView.fullDetailsView.bind(title: "Full details") } } -extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol {} +extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { + func set(votingDetails: ReferendumVotingStatusDetailsView.Model) { + rootView.votingDetailsView.view.bind(viewModel: votingDetails) + } + + func set(dAppModels: [ReferendumDAppView.Model]) { + rootView.setDApps(models: dAppModels) + } + + func set(timelineModel: ReferendumTimelineView.Model) { + rootView.timelineTableView.view.bind(viewModel: timelineModel) + } + + func set(titleModel: ReferendumDetailsTitleView.Model) { + rootView.titleView.bind(viewModel: titleModel) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 9035ff28c6..e347475395 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -3,16 +3,20 @@ import UIKit final class ReferendumDetailsViewLayout: UIView { let containerView: ScrollableContainerView = { let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) - view.stackView.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) + view.stackView.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 24, right: 16) view.stackView.isLayoutMarginsRelativeArrangement = true view.stackView.alignment = .fill return view }() let titleView = ReferendumDetailsTitleView() - let votingStatusView = ReferendumVotingStatusView() + let votingDetailsView = BlurredView() let dAppsTableView = StackTableView() - let timelineTableView = ReferendumTimelineView() + let timelineTableView: BlurredView = .create { + $0.contentInsets = .init(top: 16, left: 16, bottom: 20, right: 16) + } + + let fullDetailsView = FullDetailsRow(frame: .zero) override init(frame: CGRect) { super.init(frame: frame) @@ -31,23 +35,53 @@ final class ReferendumDetailsViewLayout: UIView { $0.edges.equalToSuperview() } + containerView.stackView.spacing = 12 containerView.stackView.addArrangedSubview(titleView) containerView.stackView.setCustomSpacing(16, after: titleView) - containerView.stackView.addArrangedSubview(votingStatusView) - containerView.stackView.setCustomSpacing(12, after: votingStatusView) - + containerView.stackView.addArrangedSubview(votingDetailsView) + containerView.stackView.addArrangedSubview(dAppsTableView) containerView.stackView.addArrangedSubview(timelineTableView) - containerView.stackView.setCustomSpacing(12, after: dAppsTableView) + containerView.stackView.addArrangedSubview(fullDetailsView) } func setDApps(models: [ReferendumDAppView.Model]) { - models.forEach { - let dAppView = ReferendumDAppCellView() - dAppView.rowContentView.bind(viewModel: $0) - dAppsTableView.addArrangedSubview(dAppView) + for model in models { + let dAppView = ReferendumDAppCellView(frame: .zero) + dAppView.rowContentView.bind(viewModel: model) + dAppsTableView.stackView.addArrangedSubview(dAppView) } } } -final class ReferendumDAppCellView: RowView, StackTableViewCellProtocol {} +final class ReferendumDAppCellView: RowView, StackTableViewCellProtocol { + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = .clear + preferredHeight = 64 + } +} + +final class FullDetailsRow: RowView>> { + let titleLabel = UILabel(style: .rowLink, textAlignment: .left) + let arrowView = UIImageView(image: R.image.iconChevronRight()) + + override init(frame _: CGRect) { + super.init( + contentView: .init(view: .init(titleView: titleLabel, valueView: arrowView)), + preferredHeight: 52 + ) + backgroundColor = .clear + } + + func bind(title: String) { + titleLabel.text = title + } +} + +extension UILabel.Style { + static let rowLink = UILabel.Style( + textColor: R.color.colorAccent(), + font: .p2Paragraph + ) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift new file mode 100644 index 0000000000..4d2c8a6d36 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift @@ -0,0 +1,62 @@ +import UIKit + +class BlurredView: UIView where TContentView: UIView { + let view: TContentView + let backgroundBlurView = TriangularedBlurView() + + var contentInsets: UIEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: 0) { + didSet { + updateLayout() + } + } + + var innerInsets: UIEdgeInsets = .zero { + didSet { + updateLayout() + } + } + + init(view: TContentView = .init()) { + self.view = view + super.init(frame: .zero) + backgroundColor = .clear + setupLayout() + } + + override init(frame: CGRect) { + view = TContentView() + super.init(frame: frame) + backgroundColor = .clear + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var intrinsicContentSize: CGSize { + .init(width: UIView.noIntrinsicMetric, height: 123) + } + + private func setupLayout() { + addSubview(backgroundBlurView) + backgroundBlurView.snp.makeConstraints { + $0.edges.equalToSuperview().inset(contentInsets) + } + + backgroundBlurView.addSubview(view) + view.snp.makeConstraints { + $0.edges.equalToSuperview().inset(innerInsets) + } + } + + private func updateLayout() { + backgroundBlurView.snp.updateConstraints { + $0.edges.equalToSuperview().inset(contentInsets) + } + view.snp.updateConstraints { + $0.edges.equalToSuperview().inset(innerInsets) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift deleted file mode 100644 index 902ba9fc76..0000000000 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Contents.swift +++ /dev/null @@ -1,135 +0,0 @@ -//: A UIKit based Playground for presenting user interface - -import UIKit -import SnapKit -import SubstrateSdk -import PlaygroundSupport - -private func registerFonts() { - registerFont(name: "PublicSans-Medium") - registerFont(name: "PublicSans-ExtraLight") - registerFont(name: "PublicSans-SemiBold") - registerFont(name: "PublicSans-Regular") - registerFont(name: "PublicSans-ExtraBold") - registerFont(name: "PublicSans-Bold") -} - -private func registerFont(name: String) { - let cfURL = Bundle.main.url( - forResource: name, - withExtension: "otf" - )! as CFURL - - CTFontManagerRegisterFontsForURL(cfURL, CTFontManagerScope.process, nil) -} - -registerFonts() -let view = UIView() -view.backgroundColor = .black -view.frame = .init( - origin: .zero, - size: .init(width: 360, height: 800) -) - -var detailsView = ReferendumVotingStatusDetailsView() -// view.addSubview(detailsView) -// detailsView.snp.makeConstraints { -// $0.centerY.equalToSuperview() -// $0.leading.trailing.equalToSuperview() -// } - -let status = ReferendumVotingStatusView.Model( - status: .init(name: "PASSING", kind: .positive), - time: .init(titleIcon: .init(title: "Approve in 03:59:59", icon: R.image.iconFire()), isUrgent: true), - title: "Voting status" -) -let votingProgress = VotingProgressView.Model( - ayeProgress: "Aye: 99.9%", - passProgress: "To pass: 50%", - nayProgress: "Nay: 0.1%", - thresholdModel: .init(titleIcon: .init(title: "Threshold reached", icon: R.image.iconCheckmark()?.withTintColor(R.color.colorDarkGreen()!)), value: 0.5), - progress: 0.9 -) -detailsView.bind(viewModel: .init( - status: status, - votingProgress: votingProgress, - aye: .init( - title: "Aye", - votes: "25,354.16 votes", - tokens: "16,492 KSM" - ), - nay: .init( - title: "Nay", - votes: "1.5 votes", - tokens: "149 KSM" - ), - buttonText: "Vote" -)) - -// var statusesView = ReferendumTimelineView() -// view.addSubview(statusesView) -// statusesView.snp.makeConstraints { -// $0.centerY.equalToSuperview() -// $0.leading.trailing.equalToSuperview() -// } -// -// statusesView.bind(viewModel: .init(title: "Timeline", statuses: [ -// .init(title: "Created", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), -// .init(title: "Created", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) -// ])) - -// let referendumDAppView = ReferendumDAppView() -// view.addSubview(referendumDAppView) -// referendumDAppView.snp.makeConstraints { -// $0.centerY.equalToSuperview() -// $0.leading.trailing.equalToSuperview() -// } -// -// let iconUrl = URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/chains/white/Polkadot.svg")! -// referendumDAppView.bind(viewModel: .init( -// icon: RemoteImageViewModel(url: iconUrl), -// title: "Polkassembly", -// subtitle: "Comment and react" -// )) - -let referendumDetailsTitleView = ReferendumDetailsTitleView() -view.addSubview(referendumDetailsTitleView) -referendumDetailsTitleView.snp.makeConstraints { - $0.centerY.equalToSuperview() - $0.leading.trailing.equalToSuperview() -} - -referendumDetailsTitleView.backgroundColor = .darkGray - -func generateMetaAccount(with chainAccounts: Set = []) -> MetaAccountModel { - MetaAccountModel( - metaId: UUID().uuidString, - name: UUID().uuidString, - substrateAccountId: Data.random(of: 32)!, - substrateCryptoType: 0, - substratePublicKey: Data.random(of: 32)!, - ethereumAddress: Data.random(of: 20)!, - ethereumPublicKey: Data.random(of: 32)!, - chainAccounts: chainAccounts, - type: .secrets - ) -} - -let wallet = generateMetaAccount() -let optIcon = wallet.walletIdenticonData().flatMap { try? PolkadotIconGenerator().generateFromAccountId($0) } -let iconViewModel = optIcon.map { DrawableIconViewModel(icon: $0) } - -referendumDetailsTitleView.bind(viewModel: - .init( - track: .init( - titleIcon: .init(title: "main agenda", icon: nil), - referendumNumber: "224" - ), - accountIcon: iconViewModel, - accountName: "RTTI-5220", - title: "Polkadot and Kusama participation in the 10th Pais Digital Chile Summit.", - description: "The Sovereign Nature Initiative transfers, Governance, Sovereign Nature Initiative (SNI) is a non-profit foundation that has" + - "brought together multiple partners and engineers from the лоалыво одыо лоаыдвлоадо", - buttonText: "Read more >" - )) -PlaygroundPage.current.liveView = view diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Bold.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Bold.otf deleted file mode 100644 index 7a2b62bd49a8a1aabae8c5b5847eb71bd977ee4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56032 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 Mdo71h?`WI+A3W~&d;kCd diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraBold.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraBold.otf deleted file mode 100644 index 09b52ddfe78a6ca5e566789dced5cff293d615f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56468 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 be?C_L5E{okKmOdzz~3hWO5sfJZIk~8Y0T9n diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraLight.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-ExtraLight.otf deleted file mode 100644 index 49b407d8d058bccba659c9e475af331f67b259d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56584 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 diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Regular.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-Regular.otf deleted file mode 100644 index d2b3f169a07a8ed7d29639ca8ee73415daa56159..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56792 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 diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-SemiBold.otf b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/Resources/PublicSans-SemiBold.otf deleted file mode 100644 index 4ab6b8904b60bbee889093bba69374c76a52e2d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56720 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 - - - \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/timeline.xctimeline b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/timeline.xctimeline deleted file mode 100644 index bf468afeca..0000000000 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/MyPlayground.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift index 62c0c61589..9b2788a0c5 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift @@ -91,6 +91,6 @@ extension ReferendumDAppView { static let horizontalSpace: CGFloat = 12 static let iconWidth: CGFloat = 48 static let iconInsets = UIEdgeInsets(top: 6, left: 6, bottom: 6, right: 6) - static let contentInsets = UIEdgeInsets(top: 16, left: 16, bottom: 0, right: 16) + static let contentInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index 6ee0d9512d..e0d7366655 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -18,12 +18,23 @@ final class ReferendumDetailsTitleView: UIView { let addressView = PolkadotIconDetailsView() let infoImageView = UIImageView() - let textView = UITextView() - let moreButton = UIButton() + let textView: UITextView = .create { + $0.isScrollEnabled = false + } + + let moreButton: UIButton = .create { + let color = R.color.colorAccent()! + $0.titleLabel?.apply(style: .rowLink) + $0.setImage( + R.image.iconChevronRight()?.tinted(with: color), + for: .normal + ) + $0.tintColor = color + $0.semanticContentAttribute = .forceRightToLeft + } override init(frame: CGRect) { super.init(frame: frame) - setupLayout() } @@ -53,13 +64,19 @@ final class ReferendumDetailsTitleView: UIView { ] ), textView, - moreButton + UIView.hStack([ + moreButton, + UIView() + ]) ] ) addSubview(content) content.snp.makeConstraints { $0.edges.equalToSuperview() } + textView.snp.makeConstraints { + $0.height.lessThanOrEqualTo(220) + } } } @@ -97,10 +114,11 @@ extension ReferendumDetailsTitleView { string: viewModel.description, attributes: descriptionAttributes ) - let referndumInfo = NSMutableAttributedString() - referndumInfo.append(titleAttributedString) - referndumInfo.append(descriptionAttributedString) - textView.attributedText = referndumInfo + let referendumInfo = NSMutableAttributedString() + referendumInfo.append(titleAttributedString) + referendumInfo.append(NSAttributedString(string: "\n")) + referendumInfo.append(descriptionAttributedString) + textView.attributedText = referendumInfo moreButton.setTitle(viewModel.buttonText, for: .normal) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift deleted file mode 100644 index f83c101f74..0000000000 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumTimelineView.swift +++ /dev/null @@ -1,174 +0,0 @@ -import UIKit -import SoraUI - -final class DotsView: UIView { - var statusesView: [BaselinedView] = [] - - override func draw(_ rect: CGRect) { - super.draw(rect) - - print("createDots") - createDots() - } - - private func createDots() { - let dotX = frame.midX - - guard let context = UIGraphicsGetCurrentContext() else { - return - } - context.setStrokeColor(R.color.colorNovaBlue()!.cgColor) - context.setFillColor(R.color.colorNovaBlue()!.cgColor) - context.setLineWidth(1) - for index in 0 ..< statusesView.count { - let dotY = statusesView[index].firstBaseline.center.y - let firstDot = UIBezierPath( - arcCenter: .init(x: dotX, y: dotY), - radius: 6, - startAngle: 0, - endAngle: 2 * .pi, - clockwise: true - ) - - firstDot.move(to: .init(x: dotX, y: dotY + 6)) - print("x1: \(dotX), y1: \(dotY + 6)") - if index + 1 >= statusesView.count { - return - } - statusesView[index].firstBaseline.layoutIfNeeded() - statusesView[index + 1].firstBaseline.layoutIfNeeded() - - print("1: \(statusesView[index].firstBaseline.frame)") - print("2: \(statusesView[index + 1].firstBaseline.frame)") - - let nextDotY = statusesView[index + 1].firstBaseline.center.y - firstDot.addLine(to: .init(x: dotX, y: nextDotY)) - firstDot.stroke() - firstDot.fill() - - let secondDot = UIBezierPath( - arcCenter: .init(x: dotX, y: nextDotY), - radius: 6, - startAngle: 0, - endAngle: 2 * .pi, - clockwise: true - ) - secondDot.stroke() - secondDot.fill() - print("x2: \(dotX), y2: \(nextDotY)") - } - } - - override var intrinsicContentSize: CGSize { - .init(width: 12, height: UIView.noIntrinsicMetric) - } -} - -final class ReferendumTimelineView: UIView { - var dotsView = DotsView() - private(set) var statusesView: [BaselinedView] = [] - var content = UIStackView() - - override init(frame: CGRect) { - super.init(frame: frame) - - setupLayout() - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupLayout() { - content = UIView.hStack( - [ - dotsView, - UIView.vStack(statusesView) - ] - ) - - addSubview(content) - content.snp.makeConstraints { - $0.edges.equalToSuperview() - } - } - - private func updateStatuses(model: Model) { - layoutIfNeeded() - statusesView = createStatusesView(from: model) - content.arrangedSubviews.forEach { - content.removeArrangedSubview($0) - } - content.addArrangedSubview(dotsView) - content.addArrangedSubview(UIView.vStack(statusesView)) - statusesView.forEach { - $0.snp.makeConstraints { make in - make.height.equalTo(44) - } - } - content.setNeedsLayout() - content.layoutIfNeeded() - dotsView.statusesView = statusesView - dotsView.setNeedsDisplay() - } - - private func createStatusesView(from model: Model) -> [BaselinedView] { - model.statuses.map { status -> BaselinedView in - switch status.subtitle { - case let .date(date): - let view = MultiValueView() - view.valueTop.text = status.title - view.valueBottom.text = date - return view - case let .interval(model): - let view = GenericMultiValueView() - view.valueTop.text = status.title - view.valueBottom.bind(viewModel: model) - return view - case .none: - let label = UILabel() - label.text = status.title - return label - } - } - } -} - -extension ReferendumTimelineView { - struct Model { - let title: String - let statuses: [Status] - - struct Status { - let title: String - let subtitle: StatusSubtitle? - let isLast: Bool - } - - enum StatusSubtitle { - case date(String) - case interval(TitleIconViewModel) - } - } - - func bind(viewModel: Model) { - updateStatuses(model: viewModel) - } -} - -protocol BaselinedView: UIView { - var firstBaseline: UIView { get } -} - -extension GenericMultiValueView: BaselinedView { - var firstBaseline: UIView { - valueTop - } -} - -extension UILabel: BaselinedView { - var firstBaseline: UIView { - self - } -} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift index 0bbd295d67..ed4f50ce83 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -12,12 +12,14 @@ final class ReferendumVotingStatusDetailsView: UIView { let nayVotesView: VoteRowView = .create { $0.apply(style: .init( - color: R.color.colorDarkGreen()!, + color: R.color.colorGreen15CF37()!, accessoryImage: R.image.iconInfo()! )) } - let voteButton = ButtonLargeControl() + let voteButton: ButtonLargeControl = .create { + $0.titleLabel.textAlignment = .center + } override init(frame: CGRect) { super.init(frame: frame) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift index 1188e81984..60365f9995 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift @@ -88,7 +88,7 @@ extension ReferendumVotingStatusView { private extension UILabel.Style { static let positiveStatusLabel = UILabel.Style( - textColor: R.color.colorDarkGreen(), + textColor: R.color.colorGreen15CF37(), font: .boldTitle2 ) static let negativeStatusLabel = UILabel.Style( diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/BaselinedView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/BaselinedView.swift new file mode 100644 index 0000000000..ba3c8e6eae --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/BaselinedView.swift @@ -0,0 +1,17 @@ +import UIKit + +protocol BaselinedView: UIView { + var firstBaseline: UIView { get } +} + +extension GenericMultiValueView: BaselinedView { + var firstBaseline: UIView { + valueTop + } +} + +extension UILabel: BaselinedView { + var firstBaseline: UIView { + self + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift new file mode 100644 index 0000000000..59ef1c8e85 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift @@ -0,0 +1,86 @@ +import UIKit +import SoraUI + +final class ReferendumTimelineView: UIView { + private(set) var statusesView: [BaselinedView] = [] + var content = UIStackView() + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + content = UIView.vStack(statusesView) + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview().inset(UIEdgeInsets(top: 0, left: 44, bottom: 0, right: 0)) + } + } + + private func updateStatuses(model: Model) { + layoutIfNeeded() + statusesView = createStatusesView(from: model) + content.arrangedSubviews.forEach { + content.removeArrangedSubview($0) + } + content.addArrangedSubview(UIView.vStack(statusesView)) + statusesView.forEach { + $0.snp.makeConstraints { make in + make.height.equalTo(44) + } + } + } + + private func createStatusesView(from model: Model) -> [BaselinedView] { + model.statuses.map { status -> BaselinedView in + switch status.subtitle { + case let .date(date): + let view = MultiValueView() + view.valueTop.text = status.title + view.valueTop.textAlignment = .left + view.valueBottom.textAlignment = .left + view.valueBottom.text = date + return view + case let .interval(model): + let view = GenericMultiValueView() + view.valueTop.text = status.title + view.valueTop.textAlignment = .left + view.valueBottom.bind(viewModel: model) + return view + case .none: + let label = UILabel() + label.text = status.title + return label + } + } + } +} + +extension ReferendumTimelineView { + struct Model { + let title: String + let statuses: [Status] + + struct Status { + let title: String + let subtitle: StatusSubtitle? + let isLast: Bool + } + + enum StatusSubtitle { + case date(String) + case interval(TitleIconViewModel) + } + } + + func bind(viewModel: Model) { + updateStatuses(model: viewModel) + } +} From 89f4ce8b7082e04e3667a2eb370fda6f93c5c35f Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 18 Oct 2022 19:17:24 +0300 Subject: [PATCH 058/229] hide view if model is nil --- novawallet.xcodeproj/project.pbxproj | 4 ++++ .../ReferendumDetailsViewLayout.swift | 2 +- .../ReferendumDetails/View/BindableView.swift | 17 +++++++++++++++++ .../View/ReferendumDetailsTitleView.swift | 2 +- .../ReferendumVotingStatusDetailsView.swift | 19 ++++++++++--------- .../ReferendumDetails/View/VoteRowView.swift | 2 +- .../Governance/View/VotingProgressView.swift | 2 +- 7 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/BindableView.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 718c9ece19..32c898e97b 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2285,6 +2285,7 @@ 88E8CF5E28E3789600C90112 /* CrowdloanEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E8CF5D28E3789600C90112 /* CrowdloanEmptyView.swift */; }; 88F19DDE28D8D0A100F6E459 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F19DDD28D8D0A100F6E459 /* Either.swift */; }; 88F19DE028D8D0F600F6E459 /* LoadableViewModelState+Addition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F19DDF28D8D0F600F6E459 /* LoadableViewModelState+Addition.swift */; }; + 88F34FD228FF045400712BDE /* BindableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FD128FF045400712BDE /* BindableView.swift */; }; 88F3A9FB9CEA464275F1115E /* ExportMnemonicViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47759907380BE9300E54DC78 /* ExportMnemonicViewFactory.swift */; }; 88F7716028BEA589008C028A /* YourWalletsIconDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7715F28BEA589008C028A /* YourWalletsIconDetailsView.swift */; }; 88F7716428BF6B59008C028A /* GenericMultiValueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7716328BF6B59008C028A /* GenericMultiValueView.swift */; }; @@ -5165,6 +5166,7 @@ 88E8CF5D28E3789600C90112 /* CrowdloanEmptyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrowdloanEmptyView.swift; sourceTree = ""; }; 88F19DDD28D8D0A100F6E459 /* Either.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Either.swift; sourceTree = ""; }; 88F19DDF28D8D0F600F6E459 /* LoadableViewModelState+Addition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoadableViewModelState+Addition.swift"; sourceTree = ""; }; + 88F34FD128FF045400712BDE /* BindableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BindableView.swift; sourceTree = ""; }; 88F7715F28BEA589008C028A /* YourWalletsIconDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsIconDetailsView.swift; sourceTree = ""; }; 88F7716328BF6B59008C028A /* GenericMultiValueView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericMultiValueView.swift; sourceTree = ""; }; 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsTitleView.swift; sourceTree = ""; }; @@ -12104,6 +12106,7 @@ 88A95FA728FAA99D00BE26F3 /* ReferendumDAppView.swift */, 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */, 887A717D28FEF10D00B13C7E /* BlurredView.swift */, + 88F34FD128FF045400712BDE /* BindableView.swift */, ); path = View; sourceTree = ""; @@ -14123,6 +14126,7 @@ 84EE2FA9289120A100A98816 /* WalletManagePresenter.swift in Sources */, 842A737727DC7AEB006EE1EA /* NetworkViewModelFactory.swift in Sources */, 848919D726FB238E004DBAD5 /* JsonDataProviderFactory.swift in Sources */, + 88F34FD228FF045400712BDE /* BindableView.swift in Sources */, 8857E03128A6A22500260BA2 /* PriceAssetInfoFactory.swift in Sources */, 846802A3265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift in Sources */, 849014C324AA87E4008F705E /* LocalAuthInteractor.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index e347475395..68987bdf65 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -13,7 +13,7 @@ final class ReferendumDetailsViewLayout: UIView { let votingDetailsView = BlurredView() let dAppsTableView = StackTableView() let timelineTableView: BlurredView = .create { - $0.contentInsets = .init(top: 16, left: 16, bottom: 20, right: 16) + $0.innerInsets = .init(top: 16, left: 16, bottom: 20, right: 16) } let fullDetailsView = FullDetailsRow(frame: .zero) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BindableView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BindableView.swift new file mode 100644 index 0000000000..e8852f5688 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BindableView.swift @@ -0,0 +1,17 @@ +import UIKit + +protocol BindableView: UIView { + associatedtype TModel + func bind(viewModel: TModel) +} + +extension BindableView { + func bindOrHide(viewModel: TModel?) { + if let viewModel = viewModel { + isHidden = false + bind(viewModel: viewModel) + } else { + isHidden = true + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index e0d7366655..3747c6c54b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -29,7 +29,7 @@ final class ReferendumDetailsTitleView: UIView { R.image.iconChevronRight()?.tinted(with: color), for: .normal ) - $0.tintColor = color + $0.setTitleColor(color, for: .normal) $0.semanticContentAttribute = .forceRightToLeft } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift index ed4f50ce83..d5c0724131 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -58,21 +58,22 @@ final class ReferendumVotingStatusDetailsView: UIView { extension ReferendumVotingStatusDetailsView { struct Model { let status: ReferendumVotingStatusView.Model - let votingProgress: VotingProgressView.Model + let votingProgress: VotingProgressView.Model? let aye: VoteRowView.Model? let nay: VoteRowView.Model? - let buttonText: String + let buttonText: String? } func bind(viewModel: Model) { statusView.bind(viewModel: viewModel.status) - votingProgressView.bind(viewModel: viewModel.votingProgress) - viewModel.aye.map { - ayeVotesView.bind(viewModel: $0) + votingProgressView.bindOrHide(viewModel: viewModel.votingProgress) + ayeVotesView.bindOrHide(viewModel: viewModel.aye) + nayVotesView.bindOrHide(viewModel: viewModel.nay) + if let buttonText = viewModel.buttonText { + voteButton.isHidden = false + voteButton.bind(title: buttonText, details: nil) + } else { + voteButton.isHidden = true } - viewModel.nay.map { - nayVotesView.bind(viewModel: $0) - } - voteButton.bind(title: viewModel.buttonText, details: nil) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift index d14704cad0..adb801a3a3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift @@ -72,7 +72,7 @@ extension VoteRowView { } } -extension VoteRowView { +extension VoteRowView: BindableView { struct Model { let title: String let votes: String diff --git a/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift index 2e683fc5b3..bb797a307e 100644 --- a/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift +++ b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift @@ -51,7 +51,7 @@ final class VotingProgressView: UIView { } } -extension VotingProgressView { +extension VotingProgressView: BindableView { struct Model { let support: TitleIconViewModel? let approval: ApprovalModel From b7fe9539e67118a67b4827a7e07968e074bdc35c Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 19 Oct 2022 11:22:00 +0500 Subject: [PATCH 059/229] add base layout --- novawallet.xcodeproj/project.pbxproj | 4 + .../Common/View/DiscreteGradientSlider.swift | 76 +++++++++++++ .../ReferendumVoteSetupViewController.swift | 20 +++- .../ReferendumVoteSetupViewLayout.swift | 105 ++++++++++++++++++ 4 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 novawallet/Common/View/DiscreteGradientSlider.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index ea1c16c1b2..33aff805a1 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1997,6 +1997,7 @@ 84E4932727325D4E000534F2 /* AssetListViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E4932627325D4E000534F2 /* AssetListViewModelFactory.swift */; }; 84E58C7D275E125100BD441A /* PublicSans-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = 84E58C7C275E124A00BD441A /* PublicSans-ExtraLight.otf */; }; 84E5D14227E32E8B00D27B1E /* AccountInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E5D14127E32E8B00D27B1E /* AccountInputView.swift */; }; + 84E63C1728FFC69A0093534A /* DiscreteGradientSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E63C1628FFC69A0093534A /* DiscreteGradientSlider.swift */; }; 84E6D57C262E2CE8000EA3F5 /* OperationCombiningService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E6D57B262E2CE8000EA3F5 /* OperationCombiningService.swift */; }; 84E731C326652B5C00D5B15A /* AttributedString+Crowdloan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E731C226652B5C00D5B15A /* AttributedString+Crowdloan.swift */; }; 84E83AA2286328660000B418 /* XcmOrmlTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E83AA1286328660000B418 /* XcmOrmlTransfer.swift */; }; @@ -4877,6 +4878,7 @@ 84E58C7C275E124A00BD441A /* PublicSans-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "PublicSans-ExtraLight.otf"; sourceTree = ""; }; 84E5CD532809315300A98DC4 /* MultiassetUserDataModel4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MultiassetUserDataModel4.xcdatamodel; sourceTree = ""; }; 84E5D14127E32E8B00D27B1E /* AccountInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountInputView.swift; sourceTree = ""; }; + 84E63C1628FFC69A0093534A /* DiscreteGradientSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscreteGradientSlider.swift; sourceTree = ""; }; 84E6D57B262E2CE8000EA3F5 /* OperationCombiningService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationCombiningService.swift; sourceTree = ""; }; 84E731C226652B5C00D5B15A /* AttributedString+Crowdloan.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Crowdloan.swift"; sourceTree = ""; }; 84E83AA1286328660000B418 /* XcmOrmlTransfer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcmOrmlTransfer.swift; sourceTree = ""; }; @@ -9514,6 +9516,7 @@ 8887813F28B7AAB700E7290F /* RoundedIconTitleView.swift */, 84E90BA028D0B51000529633 /* CheckboxControlView.swift */, 8468119328E6234B00BF54F1 /* RoundedSegmentedControl.swift */, + 84E63C1628FFC69A0093534A /* DiscreteGradientSlider.swift */, ); path = View; sourceTree = ""; @@ -15336,6 +15339,7 @@ 2A90206E273E6CA200F2D584 /* NetworkFeeConfirmView+Protocol.swift in Sources */, AEA0C8A4267B6B1900F9666F /* SelectedValidatorListProtocols.swift in Sources */, F4B39C4E27326E8400BB6E10 /* AcalaContributionSetupViewController.swift in Sources */, + 84E63C1728FFC69A0093534A /* DiscreteGradientSlider.swift in Sources */, 84EC2D18276B9DBC009B0BE1 /* PolkadotExtensionAccount.swift in Sources */, 8494D8552524633300614D8F /* WalletTransferTokenView.swift in Sources */, F4E17FCF272182E800FE36D3 /* MoonbeamAgreeRemarkRequest.swift in Sources */, diff --git a/novawallet/Common/View/DiscreteGradientSlider.swift b/novawallet/Common/View/DiscreteGradientSlider.swift new file mode 100644 index 0000000000..3a45f4c776 --- /dev/null +++ b/novawallet/Common/View/DiscreteGradientSlider.swift @@ -0,0 +1,76 @@ +import UIKit +import SoraUI + +class DiscreteGradientSlider: UIControl { + let thumbImageView: UIImageView = UIImageView() + let trackBackgroundView: MultigradientView = MultigradientView() + let trackOverlayView: RoundedView = RoundedView() + + private(set) var value: UInt = 0 + private(set) var numberOfValues: UInt = 3 + + var trackHeight: CGFloat = 8.0 { + didSet { + setNeedsLayout() + } + } + + var contentInsets: UIEdgeInsets = UIEdgeInsets(top: 16.0, left: 0.0, bottom: 16.0, right: 0.0) { + didSet { + invalidateIntrinsicContentSize() + setNeedsLayout() + } + } + + override var intrinsicContentSize: CGSize { + let contentHeight = max(thumbImageView.intrinsicContentSize.height, trackHeight) + let height = contentHeight + contentInsets.top + contentInsets.bottom + return CGSize(width: UIView.noIntrinsicMetric, height: height) + } + + var colors: [UIColor] { + trackBackgroundView.colors + } + + private var dots: [RoundedView] = [] + + override init(frame: CGRect) { + super.init(frame: frame) + + backgroundColor = .clear + + configure() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func configure() { + addSubview(trackBackgroundView) + addSubview(trackOverlayView) + addSubview(thumbImageView) + } + + private func updateThumbPosition() { + guard numberOfValues > 1 else { + return + } + + let step = bounds.height / CGFloat(numberOfValues - 1) + let positionX = CGFloat(value) * step + + let size = thumbImageView.intrinsicContentSize + + thumbImageView.frame = CGRect( + x: positionX - size.width / 2.0, + y: bounds.midY - size.height / 2.0, + width: size.width, + height: size.height + ) + } + + override func layoutSubviews() { + super.layoutSubviews() + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift index acaaf39614..ec0198a1e1 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -1,13 +1,19 @@ import UIKit +import SoraFoundation final class ReferendumVoteSetupViewController: UIViewController { typealias RootViewType = ReferendumVoteSetupViewLayout let presenter: ReferendumVoteSetupPresenterProtocol - init(presenter: ReferendumVoteSetupPresenterProtocol) { + init( + presenter: ReferendumVoteSetupPresenterProtocol, + localizationManager: LocalizationManagerProtocol + ) { self.presenter = presenter super.init(nibName: nil, bundle: nil) + + self.localizationManager = localizationManager } @available(*, unavailable) @@ -24,6 +30,18 @@ final class ReferendumVoteSetupViewController: UIViewController { presenter.setup() } + + private func setupLocalization() { + + } } extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol {} + +extension ReferendumVoteSetupViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + setupLocalization() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index 15ca69685d..35c9cc2679 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -1,12 +1,117 @@ import UIKit final class ReferendumVoteSetupViewLayout: UIView { + let containerView: ScrollableContainerView = { + let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) + view.stackView.layoutMargins = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 0.0, right: 16.0) + view.stackView.isLayoutMarginsRelativeArrangement = true + view.stackView.alignment = .fill + return view + }() + + let ayeButton: TriangularedButton = { + let button = TriangularedButton() + button.applyDefaultStyle() + button.triangularedView?.fillColor = R.color.colorGreen()! + return button + }() + + let nayButton: TriangularedButton = { + let button = TriangularedButton() + button.applyDefaultStyle() + button.triangularedView?.fillColor = R.color.colorRed()! + return button + }() + + let titleLabel: UILabel = .create { view in + view.textColor = R.color.colorWhite() + view.font = .regularSubheadline + view.numberOfLines = 0 + } + + let amountView = TitleHorizontalMultiValueView() + + let amountInputView = NewAmountInputView() + + let lockedAmountView = ReferendumVoteSetupViewLayout.createMultiValueView() + + let lockedPeriodView = ReferendumVoteSetupViewLayout.createMultiValueView() + + let feeView: NetworkFeeView = { + let view = UIFactory.default.createNetwork26FeeView() + view.verticalOffset = 13.0 + return view + }() + + let hintListView = HintListView() + override init(frame: CGRect) { super.init(frame: frame) + + backgroundColor = R.color.colorBlack() + + setupLayout() } @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } + + private func setupLayout() { + addSubview(nayButton) + nayButton.snp.makeConstraints { make in + make.leading.equalToSuperview().inset(UIConstants.horizontalInset) + make.trailing.equalTo(safeAreaLayoutGuide.snp.centerX).inset(8.0) + make.bottom.equalTo(safeAreaLayoutGuide).inset(UIConstants.actionBottomInset) + make.height.equalTo(UIConstants.actionHeight) + } + + addSubview(ayeButton) + ayeButton.snp.makeConstraints { make in + make.leading.equalTo(safeAreaLayoutGuide.snp.centerX).inset(8.0) + make.trailing.equalToSuperview().inset(UIConstants.horizontalInset) + make.bottom.equalTo(safeAreaLayoutGuide).inset(UIConstants.actionBottomInset) + make.height.equalTo(UIConstants.actionHeight) + } + + addSubview(containerView) + containerView.snp.makeConstraints { make in + make.top.leading.trailing.equalToSuperview() + make.bottom.equalTo(ayeButton.snp.top).offset(-8.0) + } + + containerView.stackView.addArrangedSubview(titleLabel) + containerView.stackView.addArrangedSubview(amountView) + containerView.stackView.addArrangedSubview(amountInputView) + + amountView.snp.makeConstraints { make in + make.height.equalTo(34.0) + } + + containerView.stackView.addArrangedSubview(amountInputView) + amountInputView.snp.makeConstraints { make in + make.height.equalTo(64) + } + + containerView.stackView.setCustomSpacing(16.0, after: amountInputView) + + containerView.stackView.addArrangedSubview(lockedAmountView) + containerView.stackView.addArrangedSubview(lockedPeriodView) + containerView.stackView.addArrangedSubview(feeView) + containerView.stackView.addArrangedSubview(hintListView) + } + + static func createMultiValueView( + ) -> GenericTitleValueView> { + let view = GenericTitleValueView>() + view.titleView.textColor = R.color.colorWhite() + view.titleView.font = .regularSubheadline + view.valueView.valueTop.textColor = R.color.colorTransparentText() + view.valueView.valueTop.font = .regularFootnote + view.valueView.valueBottom.detailsLabel.textColor = R.color.colorNovaBlue() + view.valueView.valueBottom.detailsLabel.font = .regularFootnote + + return view + } } From 1c9b74f13dd51fd2c159f01553a70e5f27de93ee Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 19 Oct 2022 11:05:26 +0300 Subject: [PATCH 060/229] added requested amount row, fixes --- novawallet.xcodeproj/project.pbxproj | 28 ++++++++ .../Common/View/GenericMultiValueView.swift | 10 ++- novawallet/Common/View/MultiValueView.swift | 4 ++ .../ReferendumDetailsProtocols.swift | 2 + .../ReferendumDetailsViewController.swift | 26 ++++++++ .../ReferendumDetailsViewLayout.swift | 55 +++++++++------- .../ReferendumDetails/View/BlurredView.swift | 2 +- .../View/ReferendumVotingStatusView.swift | 5 +- .../View/Rows/FullDetailsRow.swift | 24 +++++++ .../View/Rows/ReferendumDAppCellView.swift | 9 +++ .../View/Rows/RequestedAmountRow.swift | 41 ++++++++++++ .../View/Rows/YourVoteRow.swift | 36 ++++++++++ .../ReferendumDetails/View/VoteRowView.swift | 34 ++++++---- .../View/MultiValueView+Model.swift | 15 +++++ .../Vote/Governance/View/UILabel+Style.swift | 14 ++++ .../Vote/Governance/View/YourVoteView.swift | 65 ++++++++++++++++--- 16 files changed, 318 insertions(+), 52 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift create mode 100644 novawallet/Modules/Vote/Governance/View/MultiValueView+Model.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 32c898e97b..1691e03914 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2286,6 +2286,11 @@ 88F19DDE28D8D0A100F6E459 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F19DDD28D8D0A100F6E459 /* Either.swift */; }; 88F19DE028D8D0F600F6E459 /* LoadableViewModelState+Addition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F19DDF28D8D0F600F6E459 /* LoadableViewModelState+Addition.swift */; }; 88F34FD228FF045400712BDE /* BindableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FD128FF045400712BDE /* BindableView.swift */; }; + 88F34FD428FFE64400712BDE /* ReferendumDAppCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FD328FFE64400712BDE /* ReferendumDAppCellView.swift */; }; + 88F34FD728FFE66E00712BDE /* FullDetailsRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FD628FFE66E00712BDE /* FullDetailsRow.swift */; }; + 88F34FD928FFE68B00712BDE /* YourVoteRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FD828FFE68B00712BDE /* YourVoteRow.swift */; }; + 88F34FDB28FFE6AA00712BDE /* RequestedAmountRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FDA28FFE6AA00712BDE /* RequestedAmountRow.swift */; }; + 88F34FDD28FFE6E400712BDE /* MultiValueView+Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FDC28FFE6E400712BDE /* MultiValueView+Model.swift */; }; 88F3A9FB9CEA464275F1115E /* ExportMnemonicViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47759907380BE9300E54DC78 /* ExportMnemonicViewFactory.swift */; }; 88F7716028BEA589008C028A /* YourWalletsIconDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7715F28BEA589008C028A /* YourWalletsIconDetailsView.swift */; }; 88F7716428BF6B59008C028A /* GenericMultiValueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7716328BF6B59008C028A /* GenericMultiValueView.swift */; }; @@ -5167,6 +5172,11 @@ 88F19DDD28D8D0A100F6E459 /* Either.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Either.swift; sourceTree = ""; }; 88F19DDF28D8D0F600F6E459 /* LoadableViewModelState+Addition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoadableViewModelState+Addition.swift"; sourceTree = ""; }; 88F34FD128FF045400712BDE /* BindableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BindableView.swift; sourceTree = ""; }; + 88F34FD328FFE64400712BDE /* ReferendumDAppCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDAppCellView.swift; sourceTree = ""; }; + 88F34FD628FFE66E00712BDE /* FullDetailsRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullDetailsRow.swift; sourceTree = ""; }; + 88F34FD828FFE68B00712BDE /* YourVoteRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourVoteRow.swift; sourceTree = ""; }; + 88F34FDA28FFE6AA00712BDE /* RequestedAmountRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestedAmountRow.swift; sourceTree = ""; }; + 88F34FDC28FFE6E400712BDE /* MultiValueView+Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MultiValueView+Model.swift"; sourceTree = ""; }; 88F7715F28BEA589008C028A /* YourWalletsIconDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsIconDetailsView.swift; sourceTree = ""; }; 88F7716328BF6B59008C028A /* GenericMultiValueView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericMultiValueView.swift; sourceTree = ""; }; 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsTitleView.swift; sourceTree = ""; }; @@ -12027,6 +12037,7 @@ 88B1862928EF30A600D49854 /* YourVoteView.swift */, 889D889428F01E5B00C4320F /* ReferendumTableViewCell.swift */, 889D889628F022AA00C4320F /* UILabel+Style.swift */, + 88F34FDC28FFE6E400712BDE /* MultiValueView+Model.swift */, ); path = View; sourceTree = ""; @@ -12100,6 +12111,7 @@ isa = PBXGroup; children = ( 887A717A28FEF03000B13C7E /* Timeline */, + 88F34FD528FFE65600712BDE /* Rows */, 888A3B6628F746D200E15BD2 /* ReferendumVotingStatusDetailsView.swift */, 888A3B6428F73DC300E15BD2 /* ReferendumVotingStatusView.swift */, 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */, @@ -12174,6 +12186,17 @@ path = View; sourceTree = ""; }; + 88F34FD528FFE65600712BDE /* Rows */ = { + isa = PBXGroup; + children = ( + 88F34FD328FFE64400712BDE /* ReferendumDAppCellView.swift */, + 88F34FD628FFE66E00712BDE /* FullDetailsRow.swift */, + 88F34FD828FFE68B00712BDE /* YourVoteRow.swift */, + 88F34FDA28FFE6AA00712BDE /* RequestedAmountRow.swift */, + ); + path = Rows; + sourceTree = ""; + }; 8C1DCF40C8BE3290D4BB9843 /* ParaStkStakeConfirm */ = { isa = PBXGroup; children = ( @@ -14369,6 +14392,7 @@ AEE0C43A272A8B1F009F9AD5 /* AddChainAccount+AccountCreateWireframe.swift in Sources */, 84038FF226FFBE1900C73F3F /* JsonLocalSubscriptionHandler.swift in Sources */, 842898D1265A955A002D5D65 /* ImageViewModel.swift in Sources */, + 88F34FDB28FFE6AA00712BDE /* RequestedAmountRow.swift in Sources */, 8490145324A93FD1008F705E /* FearlessLoadingViewFactory.swift in Sources */, 8472976C260B1CAD009B86D0 /* InitiatedBondingConfirmInteractor.swift in Sources */, 84EBC55F24F71D6A00459D15 /* UITableViewCell+ReorderColor.swift in Sources */, @@ -14593,6 +14617,7 @@ 84C74363251E4C2F009576C6 /* DummySigner.swift in Sources */, 8454C26A2632B8CE00657DAD /* BalanceDepositEvent.swift in Sources */, 84DD5F3E263DE5FF00425ACF /* DataValidationProtocols.swift in Sources */, + 88F34FD928FFE68B00712BDE /* YourVoteRow.swift in Sources */, 84D8F15F24D8179000AF43E9 /* TitleWithSubtitleViewModel.swift in Sources */, AEE5FB0126415E2A002B8FDC /* StakingRebondSetupInteractor.swift in Sources */, 84C1B98624F5424700FE5470 /* ChainAccountViewModelFactory.swift in Sources */, @@ -15852,6 +15877,7 @@ 844CB57A26FA706C00396E13 /* ChainAssetDisplayInfo.swift in Sources */, 848DAEF7282274E700D56F55 /* ParachainStakingRemoteSubscriptionService.swift in Sources */, 845B821F26EF8E8900D25C72 /* ManagedMetaAccountModel.swift in Sources */, + 88F34FD428FFE64400712BDE /* ReferendumDAppCellView.swift in Sources */, 8430AB1226023C9F005B1066 /* PendingBondedState.swift in Sources */, 88421059289BBA8D00306F2C /* CurrencyViewFactory.swift in Sources */, 841E6AFE25EC12DE0007DDFE /* SelectedValidatorInfo.swift in Sources */, @@ -16050,6 +16076,7 @@ 84ED6BE428698D2E00B3C558 /* TransferCrossChainConfirmInteractor.swift in Sources */, DBA436B3B1C90965FE8F9B79 /* YourValidatorListPresenter.swift in Sources */, E7CAD629FF0D4E97594F7A05 /* YourValidatorListInteractor.swift in Sources */, + 88F34FD728FFE66E00712BDE /* FullDetailsRow.swift in Sources */, 8466780F27EB2939007935D3 /* OnChainTransferPresenter.swift in Sources */, 84466B3528B6731B00FA1E0D /* LedgerSigningWrapper.swift in Sources */, F4223ED127329767003D8E4E /* AcalaTransferRequest.swift in Sources */, @@ -16522,6 +16549,7 @@ A748D64F6048192E16E5BE44 /* ParaStkUnstakeConfirmViewLayout.swift in Sources */, A14308E2633921838166C843 /* ParaStkUnstakeConfirmViewFactory.swift in Sources */, 135E979B52DC1BD29A5FC389 /* ParaStkRedeemProtocols.swift in Sources */, + 88F34FDD28FFE6E400712BDE /* MultiValueView+Model.swift in Sources */, 54D334605E9A7C71A4873CFC /* ParaStkRedeemWireframe.swift in Sources */, 413CCB7C7B22831147B8E815 /* ParaStkRedeemPresenter.swift in Sources */, 35F9157CAA182493B2F0E1D3 /* ParaStkRedeemInteractor.swift in Sources */, diff --git a/novawallet/Common/View/GenericMultiValueView.swift b/novawallet/Common/View/GenericMultiValueView.swift index 31cab5df85..b4e3f0f962 100644 --- a/novawallet/Common/View/GenericMultiValueView.swift +++ b/novawallet/Common/View/GenericMultiValueView.swift @@ -10,7 +10,7 @@ class GenericMultiValueView: UIView { return label }() - let valueBottom = BottomView() + let valueBottom: BottomView var spacing: CGFloat { get { @@ -28,7 +28,15 @@ class GenericMultiValueView: UIView { return view }() + init(valueBottom: BottomView = BottomView()) { + self.valueBottom = valueBottom + super.init(frame: .zero) + + setupLayout() + } + override init(frame: CGRect) { + valueBottom = .init() super.init(frame: frame) setupLayout() diff --git a/novawallet/Common/View/MultiValueView.swift b/novawallet/Common/View/MultiValueView.swift index 53e81cef15..2fb0c50521 100644 --- a/novawallet/Common/View/MultiValueView.swift +++ b/novawallet/Common/View/MultiValueView.swift @@ -10,6 +10,10 @@ class MultiValueView: GenericMultiValueView { valueBottom.textAlignment = .right } + convenience init() { + self.init(frame: .zero) + } + @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 11e068f795..dfa2e1bcf7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -3,6 +3,8 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { func set(dAppModels: [ReferendumDAppView.Model]) func set(timelineModel: ReferendumTimelineView.Model) func set(titleModel: ReferendumDetailsTitleView.Model) + func set(yourVoteModel: YourVoteRow.Model?) + func set(requestedAmount: RequestedAmountRow.Model?) } protocol ReferendumDetailsPresenterProtocol: AnyObject { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 466480a1f5..28a71677ed 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -103,6 +103,16 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { ])) rootView.fullDetailsView.bind(title: "Full details") + + set(yourVoteModel: .init( + vote: .init(title: "AYE", description: "Your vote"), + amount: .init(topValue: "30 votes", bottomValue: "10 KSM × 3x") + )) + + set(requestedAmount: .init( + title: "Requested amount", + amount: .init(topValue: "1,000 KSM", bottomValue: "$38,230") + )) } } @@ -122,4 +132,20 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { func set(titleModel: ReferendumDetailsTitleView.Model) { rootView.titleView.bind(viewModel: titleModel) } + + func set(yourVoteModel: YourVoteRow.Model?) { + if let yourVoteModel = yourVoteModel { + rootView.setYourVote(model: yourVoteModel) + } else { + rootView.removeYourVote() + } + } + + func set(requestedAmount: RequestedAmountRow.Model?) { + if let requestedAmount = requestedAmount { + rootView.setRequestedAmount(model: requestedAmount) + } else { + rootView.removeRequestedAmount() + } + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 68987bdf65..5f1a0b2c19 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -16,6 +16,9 @@ final class ReferendumDetailsViewLayout: UIView { $0.innerInsets = .init(top: 16, left: 16, bottom: 20, right: 16) } + var yourVoteRow: YourVoteRow? + var requestedAmountRow: RequestedAmountRow? + let fullDetailsView = FullDetailsRow(frame: .zero) override init(frame: CGRect) { @@ -46,42 +49,44 @@ final class ReferendumDetailsViewLayout: UIView { } func setDApps(models: [ReferendumDAppView.Model]) { + dAppsTableView.clear() + for model in models { let dAppView = ReferendumDAppCellView(frame: .zero) dAppView.rowContentView.bind(viewModel: model) dAppsTableView.stackView.addArrangedSubview(dAppView) } } -} -final class ReferendumDAppCellView: RowView, StackTableViewCellProtocol { - override init(frame: CGRect) { - super.init(frame: frame) - backgroundColor = .clear - preferredHeight = 64 + func setYourVote(model: YourVoteRow.Model) { + if yourVoteRow == nil { + let yourVoteView = YourVoteRow(frame: .zero) + containerView.stackView.addArrangedSubview(yourVoteView) + yourVoteRow = yourVoteView + } + yourVoteRow?.bind(viewModel: model) } -} -final class FullDetailsRow: RowView>> { - let titleLabel = UILabel(style: .rowLink, textAlignment: .left) - let arrowView = UIImageView(image: R.image.iconChevronRight()) - - override init(frame _: CGRect) { - super.init( - contentView: .init(view: .init(titleView: titleLabel, valueView: arrowView)), - preferredHeight: 52 - ) - backgroundColor = .clear + func removeYourVote() { + guard let yourVoteRow = yourVoteRow else { + return + } + containerView.stackView.removeArrangedSubview(yourVoteRow) } - func bind(title: String) { - titleLabel.text = title + func setRequestedAmount(model: RequestedAmountRow.Model) { + if requestedAmountRow == nil { + let requestedAmountView = RequestedAmountRow(frame: .zero) + containerView.stackView.addArrangedSubview(requestedAmountView) + requestedAmountRow = requestedAmountView + } + requestedAmountRow?.bind(viewModel: model) } -} -extension UILabel.Style { - static let rowLink = UILabel.Style( - textColor: R.color.colorAccent(), - font: .p2Paragraph - ) + func removeRequestedAmount() { + guard let requestedAmountRow = requestedAmountRow else { + return + } + containerView.stackView.removeArrangedSubview(requestedAmountRow) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift index 4d2c8a6d36..0badf11d76 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift @@ -4,7 +4,7 @@ class BlurredView: UIView where TContentView: UIView { let view: TContentView let backgroundBlurView = TriangularedBlurView() - var contentInsets: UIEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: 0) { + var contentInsets: UIEdgeInsets = .zero { didSet { updateLayout() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift index 60365f9995..409e5021f6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift @@ -95,8 +95,5 @@ private extension UILabel.Style { textColor: R.color.colorRedFF3A69(), font: .boldTitle2 ) - static let title = UILabel.Style( - textColor: R.color.colorWhite64()!, - font: .regularFootnote - ) + static let title = UILabel.Style.footnoteWhite64 } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift new file mode 100644 index 0000000000..6de2a713ca --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift @@ -0,0 +1,24 @@ +import UIKit + +final class FullDetailsRow: RowView> { + let titleLabel = UILabel(style: .rowLink, textAlignment: .left) + let arrowView = UIImageView(image: R.image.iconChevronRight()) + lazy var contentMultiValueView = GenericTitleValueView( + titleView: titleLabel, + valueView: arrowView + ) + + override init(frame: CGRect) { + super.init(frame: frame) + + contentView = contentMultiValueView + backgroundView = TriangularedBlurView() + contentInsets = .init(top: 14, left: 16, bottom: 14, right: 16) + preferredHeight = 52 + backgroundColor = .clear + } + + func bind(title: String) { + titleLabel.text = title + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift new file mode 100644 index 0000000000..206e977dd9 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift @@ -0,0 +1,9 @@ +import UIKit + +final class ReferendumDAppCellView: RowView, StackTableViewCellProtocol { + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = .clear + preferredHeight = 64 + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift new file mode 100644 index 0000000000..8f45a79033 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift @@ -0,0 +1,41 @@ +import UIKit + +final class RequestedAmountRow: RowView>, BindableView { + struct Model { + let title: String + let amount: MultiValueView.Model + } + + var titleLabel: UILabel { rowContentView.valueTop } + + let amountView: MultiValueView = .create { + $0.apply(style: .accentAmount) + $0.valueTop.textAlignment = .left + $0.valueBottom.textAlignment = .left + } + + lazy var contentMultiValueView = GenericMultiValueView(valueBottom: amountView) + + override init(frame: CGRect) { + super.init(frame: frame) + + setup() + } + + private func setup() { + contentView = contentMultiValueView + preferredHeight = 102 + rowContentView.spacing = 2 + rowContentView.valueBottom.spacing = 2 + titleLabel.apply(style: .footnoteWhite64) + titleLabel.textAlignment = .left + backgroundView = TriangularedBlurView() + contentInsets = .init(top: 16, left: 16, bottom: 16, right: 16) + backgroundColor = .clear + } + + func bind(viewModel: Model) { + titleLabel.text = viewModel.title + amountView.bind(viewModel: viewModel.amount) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift new file mode 100644 index 0000000000..303114d30d --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift @@ -0,0 +1,36 @@ +import UIKit + +final class YourVoteRow: RowView>, BindableView { + + struct Model { + let vote: YourVoteView.Model + let amount: MultiValueView.Model + } + + let voteView: YourVoteView = .create { + $0.apply(style: .ayeInverse) + } + + let amountView: MultiValueView = .create { + $0.apply(style: .rowContrasted) + } + + lazy var contentMultiValueView = GenericTitleValueView( + titleView: voteView, + valueView: amountView + ) + + override init(frame: CGRect) { + super.init(frame: frame) + contentView = contentMultiValueView + backgroundView = TriangularedBlurView() + contentInsets = .init(top: 9, left: 16, bottom: 9, right: 16) + preferredHeight = 52 + backgroundColor = .clear + } + + func bind(viewModel: Model) { + voteView.bind(viewModel: viewModel.vote) + amountView.bind(viewModel: viewModel.amount) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift index adb801a3a3..611e61d911 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift @@ -90,17 +90,6 @@ extension MultiValueView { struct Style { let topLabel: UILabel.Style let bottomLabel: UILabel.Style - - static let rowContrasted = Style( - topLabel: .init( - textColor: R.color.colorWhite(), - font: .regularFootnote - ), - bottomLabel: .init( - textColor: R.color.colorWhite64(), - font: .caption1 - ) - ) } func apply(style: Style) { @@ -109,6 +98,29 @@ extension MultiValueView { } } +extension MultiValueView.Style { + static let rowContrasted = MultiValueView.Style( + topLabel: .init( + textColor: R.color.colorWhite(), + font: .regularFootnote + ), + bottomLabel: .init( + textColor: R.color.colorWhite64(), + font: .caption1 + ) + ) + static let accentAmount = MultiValueView.Style( + topLabel: .init( + textColor: R.color.colorWhite(), + font: .boldTitle1 + ), + bottomLabel: .init( + textColor: R.color.colorWhite64(), + font: .regularBody + ) + ) +} + extension UILabel.Style { static let rowTitle = UILabel.Style(textColor: R.color.colorWhite(), font: .regularFootnote) } diff --git a/novawallet/Modules/Vote/Governance/View/MultiValueView+Model.swift b/novawallet/Modules/Vote/Governance/View/MultiValueView+Model.swift new file mode 100644 index 0000000000..3e85a9c9a1 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/MultiValueView+Model.swift @@ -0,0 +1,15 @@ +import UIKit + +extension MultiValueView: BindableView { + struct Model { + let topValue: String + let bottomValue: String? + } + + func bind(viewModel: Model) { + bind( + topValue: viewModel.topValue, + bottomValue: viewModel.bottomValue + ) + } +} diff --git a/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift index 626add47d9..05f3374f37 100644 --- a/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift +++ b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift @@ -52,3 +52,17 @@ extension IconDetailsView { detailsLabel.text = viewModel?.title } } + +extension UILabel.Style { + static let footnoteWhite64 = UILabel.Style( + textColor: R.color.colorWhite64()!, + font: .regularFootnote + ) +} + +extension UILabel.Style { + static let rowLink = UILabel.Style( + textColor: R.color.colorAccent(), + font: .p2Paragraph + ) +} diff --git a/novawallet/Modules/Vote/Governance/View/YourVoteView.swift b/novawallet/Modules/Vote/Governance/View/YourVoteView.swift index 1ded7b6501..bc6bbf94aa 100644 --- a/novawallet/Modules/Vote/Governance/View/YourVoteView.swift +++ b/novawallet/Modules/Vote/Governance/View/YourVoteView.swift @@ -3,11 +3,11 @@ import UIKit final class YourVotesView: UIView { let topLine = createSeparator(color: R.color.colorWhite8()) let ayeView: YourVoteView = .create { - $0.typeView.titleLabel.apply(style: .ayeType) + $0.apply(style: .aye) } let nayView: YourVoteView = .create { - $0.typeView.titleLabel.apply(style: .nayType) + $0.apply(style: .nay) } override init(frame: CGRect) { @@ -61,6 +61,13 @@ final class YourVoteView: UIView { } let voteLabel = UILabel(style: .votes, textAlignment: .left) + lazy var content: UIStackView = UIView.hStack( + spacing: 6, + [ + typeView, + voteLabel + ] + ) override init(frame: CGRect) { super.init(frame: frame) @@ -74,14 +81,6 @@ final class YourVoteView: UIView { } private func setupLayout() { - let content = UIView.hStack( - spacing: 6, - [ - typeView, - voteLabel - ] - ) - voteLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) addSubview(content) content.snp.makeConstraints { @@ -102,6 +101,52 @@ extension YourVoteView { } } +extension YourVoteView { + struct Style { + let voteLabel: UILabel.Style + let typeView: UILabel.Style + let mode: Mode + + enum Mode { + case titleType, typeTitle + } + } + + func apply(style: Style) { + voteLabel.apply(style: style.voteLabel) + typeView.titleLabel.apply(style: style.typeView) + switch style.mode { + case .titleType: + content.semanticContentAttribute = .forceRightToLeft + case .typeTitle: + content.semanticContentAttribute = .unspecified + } + } +} + +extension YourVoteView.Style { + static let aye = YourVoteView.Style( + voteLabel: .votes, + typeView: .ayeType, + mode: .typeTitle + ) + static let nay = YourVoteView.Style( + voteLabel: .votes, + typeView: .ayeType, + mode: .typeTitle + ) + static let ayeInverse = YourVoteView.Style( + voteLabel: .votes, + typeView: .ayeType, + mode: .titleType + ) + static let nayInverse = YourVoteView.Style( + voteLabel: .votes, + typeView: .ayeType, + mode: .titleType + ) +} + extension UILabel.Style { static let ayeType = UILabel.Style( textColor: R.color.colorGreen15CF37()!, From 5800b8adefa4b2432a09029060e2dd5076604bfc Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 19 Oct 2022 11:23:05 +0300 Subject: [PATCH 061/229] remove blurred view --- novawallet.xcodeproj/project.pbxproj | 12 ++-- .../ReferendumDetailsViewLayout.swift | 6 +- .../ReferendumDetails/View/BindableView.swift | 8 +++ .../ReferendumDetails/View/BlurredView.swift | 62 ------------------- .../ReferendumVotingStatusDetailsView.swift | 2 +- .../View/Rows/RequestedAmountRow.swift | 2 +- .../View/Rows/TimelineRow.swift | 14 +++++ .../View/Rows/VotingDetailsRow.swift | 14 +++++ .../View/Rows/YourVoteRow.swift | 3 +- .../Timeline/ReferendumTimelineView.swift | 2 +- 10 files changed, 50 insertions(+), 75 deletions(-) delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 1691e03914..59cfbeb524 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2235,7 +2235,6 @@ 8860F3E8289D7CF400C0BF86 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8860F3E7289D7CF400C0BF86 /* Atomic.swift */; }; 886E8CF81EF2566D98D9693E /* ExportSeedViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FA66143B25AA70B02CE461 /* ExportSeedViewFactory.swift */; }; 887A717C28FEF03E00B13C7E /* BaselinedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887A717B28FEF03E00B13C7E /* BaselinedView.swift */; }; - 887A717E28FEF10D00B13C7E /* BlurredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887A717D28FEF10D00B13C7E /* BlurredView.swift */; }; 887AFC8728BC95F0002A0422 /* MetaAccountChainResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887AFC8628BC95F0002A0422 /* MetaAccountChainResponse.swift */; }; 887AFC8C28BCB314002A0422 /* PolkadotIconDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887AFC8928BCB313002A0422 /* PolkadotIconDetailsView.swift */; }; 887AFC8D28BCB314002A0422 /* SelectableIconSubtitleCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887AFC8A28BCB313002A0422 /* SelectableIconSubtitleCollectionViewCell.swift */; }; @@ -2291,6 +2290,8 @@ 88F34FD928FFE68B00712BDE /* YourVoteRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FD828FFE68B00712BDE /* YourVoteRow.swift */; }; 88F34FDB28FFE6AA00712BDE /* RequestedAmountRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FDA28FFE6AA00712BDE /* RequestedAmountRow.swift */; }; 88F34FDD28FFE6E400712BDE /* MultiValueView+Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FDC28FFE6E400712BDE /* MultiValueView+Model.swift */; }; + 88F34FDF28FFEAE500712BDE /* TimelineRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FDE28FFEAE500712BDE /* TimelineRow.swift */; }; + 88F34FE128FFEAFD00712BDE /* VotingDetailsRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F34FE028FFEAFD00712BDE /* VotingDetailsRow.swift */; }; 88F3A9FB9CEA464275F1115E /* ExportMnemonicViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47759907380BE9300E54DC78 /* ExportMnemonicViewFactory.swift */; }; 88F7716028BEA589008C028A /* YourWalletsIconDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7715F28BEA589008C028A /* YourWalletsIconDetailsView.swift */; }; 88F7716428BF6B59008C028A /* GenericMultiValueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F7716328BF6B59008C028A /* GenericMultiValueView.swift */; }; @@ -5120,7 +5121,6 @@ 8860F3E7289D7CF400C0BF86 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; 88787F0328DB3A7B00B115AB /* SubstrateDataModel2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SubstrateDataModel2.xcdatamodel; sourceTree = ""; }; 887A717B28FEF03E00B13C7E /* BaselinedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaselinedView.swift; sourceTree = ""; }; - 887A717D28FEF10D00B13C7E /* BlurredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurredView.swift; sourceTree = ""; }; 887AFC8628BC95F0002A0422 /* MetaAccountChainResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaAccountChainResponse.swift; sourceTree = ""; }; 887AFC8928BCB313002A0422 /* PolkadotIconDetailsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PolkadotIconDetailsView.swift; sourceTree = ""; }; 887AFC8A28BCB313002A0422 /* SelectableIconSubtitleCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectableIconSubtitleCollectionViewCell.swift; sourceTree = ""; }; @@ -5177,6 +5177,8 @@ 88F34FD828FFE68B00712BDE /* YourVoteRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourVoteRow.swift; sourceTree = ""; }; 88F34FDA28FFE6AA00712BDE /* RequestedAmountRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestedAmountRow.swift; sourceTree = ""; }; 88F34FDC28FFE6E400712BDE /* MultiValueView+Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MultiValueView+Model.swift"; sourceTree = ""; }; + 88F34FDE28FFEAE500712BDE /* TimelineRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineRow.swift; sourceTree = ""; }; + 88F34FE028FFEAFD00712BDE /* VotingDetailsRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VotingDetailsRow.swift; sourceTree = ""; }; 88F7715F28BEA589008C028A /* YourWalletsIconDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsIconDetailsView.swift; sourceTree = ""; }; 88F7716328BF6B59008C028A /* GenericMultiValueView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericMultiValueView.swift; sourceTree = ""; }; 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsTitleView.swift; sourceTree = ""; }; @@ -12117,7 +12119,6 @@ 88B560BB28F80DCB00A5EB59 /* VoteRowView.swift */, 88A95FA728FAA99D00BE26F3 /* ReferendumDAppView.swift */, 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */, - 887A717D28FEF10D00B13C7E /* BlurredView.swift */, 88F34FD128FF045400712BDE /* BindableView.swift */, ); path = View; @@ -12193,6 +12194,8 @@ 88F34FD628FFE66E00712BDE /* FullDetailsRow.swift */, 88F34FD828FFE68B00712BDE /* YourVoteRow.swift */, 88F34FDA28FFE6AA00712BDE /* RequestedAmountRow.swift */, + 88F34FDE28FFEAE500712BDE /* TimelineRow.swift */, + 88F34FE028FFEAFD00712BDE /* VotingDetailsRow.swift */, ); path = Rows; sourceTree = ""; @@ -14893,7 +14896,6 @@ 84466B4028B77B4500FA1E0D /* SignatureVerificationWrapper.swift in Sources */, 844DBC62274D1E29009F8351 /* SecretTypeTableViewCell.swift in Sources */, 847297A2260B3146009B86D0 /* ChangeTargetsSelectValidatorsStartWireframe.swift in Sources */, - 887A717E28FEF10D00B13C7E /* BlurredView.swift in Sources */, 849D755B2756910A007726C3 /* RoundedView+Style.swift in Sources */, 84038FEC26FFBA4D00C73F3F /* PriceLocalStorageSubscriber.swift in Sources */, 841221A428F0A3F200715C82 /* ReferendumAccountVoteLocal.swift in Sources */, @@ -15569,6 +15571,7 @@ 84C4C2F9255DB9510045B582 /* PinChangeInteractor.swift in Sources */, 8473F4B2282BD584007CC55A /* StakingRelaychainPresenter.swift in Sources */, 84CA68D726BE9E6F003B9453 /* ChainSyncService.swift in Sources */, + 88F34FE128FFEAFD00712BDE /* VotingDetailsRow.swift in Sources */, 84466B3E28B76A3E00FA1E0D /* LedgerPerformOperationPresenter.swift in Sources */, 8423B0E8251B2DAD00B8687C /* SubstrateOperationFactory.swift in Sources */, 84969732251CE71500C39524 /* WalletAssetId.swift in Sources */, @@ -16025,6 +16028,7 @@ 847F2D5927AB201200AFD476 /* GradientIconView.swift in Sources */, 84EBFCEE285E82BB0006327E /* XcmExecute.swift in Sources */, 849976C627B2B73900B14A6C /* DAppMetamaskStateMachine.swift in Sources */, + 88F34FDF28FFEAE500712BDE /* TimelineRow.swift in Sources */, 847F2D4427A9822200AFD476 /* AssetIconView.swift in Sources */, 20B2942A4241F6713A1C70D9 /* StakingRewardDetailsViewFactory.swift in Sources */, 84F13F0A26F14122006725FF /* ChainAsset.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 5f1a0b2c19..88c73887e8 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -10,11 +10,9 @@ final class ReferendumDetailsViewLayout: UIView { }() let titleView = ReferendumDetailsTitleView() - let votingDetailsView = BlurredView() + let votingDetailsView = VotingDetailsRow() let dAppsTableView = StackTableView() - let timelineTableView: BlurredView = .create { - $0.innerInsets = .init(top: 16, left: 16, bottom: 20, right: 16) - } + let timelineTableView = TimelineRow() var yourVoteRow: YourVoteRow? var requestedAmountRow: RequestedAmountRow? diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BindableView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BindableView.swift index e8852f5688..6da0810523 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BindableView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BindableView.swift @@ -15,3 +15,11 @@ extension BindableView { } } } + +extension RowView: BindableView where T: BindableView { + typealias TModel = T.TModel + + func bind(viewModel: TModel) { + rowContentView.bind(viewModel: viewModel) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift deleted file mode 100644 index 0badf11d76..0000000000 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift +++ /dev/null @@ -1,62 +0,0 @@ -import UIKit - -class BlurredView: UIView where TContentView: UIView { - let view: TContentView - let backgroundBlurView = TriangularedBlurView() - - var contentInsets: UIEdgeInsets = .zero { - didSet { - updateLayout() - } - } - - var innerInsets: UIEdgeInsets = .zero { - didSet { - updateLayout() - } - } - - init(view: TContentView = .init()) { - self.view = view - super.init(frame: .zero) - backgroundColor = .clear - setupLayout() - } - - override init(frame: CGRect) { - view = TContentView() - super.init(frame: frame) - backgroundColor = .clear - setupLayout() - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override var intrinsicContentSize: CGSize { - .init(width: UIView.noIntrinsicMetric, height: 123) - } - - private func setupLayout() { - addSubview(backgroundBlurView) - backgroundBlurView.snp.makeConstraints { - $0.edges.equalToSuperview().inset(contentInsets) - } - - backgroundBlurView.addSubview(view) - view.snp.makeConstraints { - $0.edges.equalToSuperview().inset(innerInsets) - } - } - - private func updateLayout() { - backgroundBlurView.snp.updateConstraints { - $0.edges.equalToSuperview().inset(contentInsets) - } - view.snp.updateConstraints { - $0.edges.equalToSuperview().inset(innerInsets) - } - } -} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift index d5c0724131..7ffb49f779 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -55,7 +55,7 @@ final class ReferendumVotingStatusDetailsView: UIView { } } -extension ReferendumVotingStatusDetailsView { +extension ReferendumVotingStatusDetailsView: BindableView { struct Model { let status: ReferendumVotingStatusView.Model let votingProgress: VotingProgressView.Model? diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift index 8f45a79033..546764652e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift @@ -1,6 +1,6 @@ import UIKit -final class RequestedAmountRow: RowView>, BindableView { +final class RequestedAmountRow: RowView> { struct Model { let title: String let amount: MultiValueView.Model diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift new file mode 100644 index 0000000000..24700e39f1 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift @@ -0,0 +1,14 @@ +import UIKit + +final class TimelineRow: RowView { + let referendumTimelineView = ReferendumTimelineView() + + override init(frame: CGRect) { + super.init(frame: frame) + + contentView = referendumTimelineView + backgroundView = TriangularedBlurView() + contentInsets = .init(top: 16, left: 16, bottom: 20, right: 16) + backgroundColor = .clear + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift new file mode 100644 index 0000000000..3f0d15696b --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift @@ -0,0 +1,14 @@ +import UIKit + +final class VotingDetailsRow: RowView { + let referendumVotingStatusDetailsView = ReferendumVotingStatusDetailsView() + + override init(frame: CGRect) { + super.init(frame: frame) + + contentView = referendumVotingStatusDetailsView + backgroundView = TriangularedBlurView() + contentInsets = .init(top: 16, left: 16, bottom: 20, right: 16) + backgroundColor = .clear + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift index 303114d30d..7befd6c955 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift @@ -1,7 +1,6 @@ import UIKit -final class YourVoteRow: RowView>, BindableView { - +final class YourVoteRow: RowView> { struct Model { let vote: YourVoteView.Model let amount: MultiValueView.Model diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift index 59ef1c8e85..cd6ab3845c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift @@ -63,7 +63,7 @@ final class ReferendumTimelineView: UIView { } } -extension ReferendumTimelineView { +extension ReferendumTimelineView: BindableView { struct Model { let title: String let statuses: [Status] From 0df17b1f77af4254d784555f3373e5f52d40582e Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 19 Oct 2022 11:33:48 +0300 Subject: [PATCH 062/229] buildfix --- .../ReferendumDetailsViewController.swift | 4 ++-- .../ReferendumDetails/ReferendumDetailsViewLayout.swift | 8 ++++---- .../ReferendumDetails/View/Rows/VotingDetailsRow.swift | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 28a71677ed..785cf2c3de 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -118,7 +118,7 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { func set(votingDetails: ReferendumVotingStatusDetailsView.Model) { - rootView.votingDetailsView.view.bind(viewModel: votingDetails) + rootView.votingDetailsRow.bind(viewModel: votingDetails) } func set(dAppModels: [ReferendumDAppView.Model]) { @@ -126,7 +126,7 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { } func set(timelineModel: ReferendumTimelineView.Model) { - rootView.timelineTableView.view.bind(viewModel: timelineModel) + rootView.timelineRow.bind(viewModel: timelineModel) } func set(titleModel: ReferendumDetailsTitleView.Model) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 88c73887e8..5d16250210 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -10,9 +10,9 @@ final class ReferendumDetailsViewLayout: UIView { }() let titleView = ReferendumDetailsTitleView() - let votingDetailsView = VotingDetailsRow() + let votingDetailsRow = VotingDetailsRow(frame: .zero) let dAppsTableView = StackTableView() - let timelineTableView = TimelineRow() + let timelineRow = TimelineRow(frame: .zero) var yourVoteRow: YourVoteRow? var requestedAmountRow: RequestedAmountRow? @@ -40,9 +40,9 @@ final class ReferendumDetailsViewLayout: UIView { containerView.stackView.addArrangedSubview(titleView) containerView.stackView.setCustomSpacing(16, after: titleView) - containerView.stackView.addArrangedSubview(votingDetailsView) + containerView.stackView.addArrangedSubview(votingDetailsRow) containerView.stackView.addArrangedSubview(dAppsTableView) - containerView.stackView.addArrangedSubview(timelineTableView) + containerView.stackView.addArrangedSubview(timelineRow) containerView.stackView.addArrangedSubview(fullDetailsView) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift index 3f0d15696b..a3619c562d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift @@ -8,7 +8,6 @@ final class VotingDetailsRow: RowView { contentView = referendumVotingStatusDetailsView backgroundView = TriangularedBlurView() - contentInsets = .init(top: 16, left: 16, bottom: 20, right: 16) backgroundColor = .clear } } From 4112c9c1975ed64cc59c43bb98a0494a5e871462 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 20 Oct 2022 01:03:33 +0500 Subject: [PATCH 063/229] fix slider --- novawallet.xcodeproj/project.pbxproj | 16 + .../colorSliderOverlay.colorset/Contents.json | 20 ++ .../iconSliderThumb.imageset/Contents.json | 12 + .../iconSliderThumb.pdf | Bin 0 -> 9430 bytes .../View/DiscreteGradientSlider+Style.swift | 33 ++ .../Common/View/DiscreteGradientSlider.swift | 281 ++++++++++++++++-- .../ReferendumVoteSetupProtocols.swift | 2 +- .../ReferendumVoteSetupViewController.swift | 4 +- .../ReferendumVoteSetupViewFactory.swift | 16 +- .../ReferendumVoteSetupViewLayout.swift | 9 +- .../View/ReferendumConvictionView.swift | 68 +++++ .../Referendums/ReferendumsWireframe.swift | 2 +- 12 files changed, 436 insertions(+), 27 deletions(-) create mode 100644 novawallet/Assets.xcassets/colorSliderOverlay.colorset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconSliderThumb.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconSliderThumb.imageset/iconSliderThumb.pdf create mode 100644 novawallet/Common/View/DiscreteGradientSlider+Style.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 33aff805a1..92e9265409 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2119,6 +2119,8 @@ 84F6B6432619A8480038F10D /* SubscanConcreteExtrinsicsData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F6B6422619A8480038F10D /* SubscanConcreteExtrinsicsData.swift */; }; 84F6B6482619A87C0038F10D /* ExtrinsicIndexWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F6B6472619A87C0038F10D /* ExtrinsicIndexWrapper.swift */; }; 84F6B6502619E1ED0038F10D /* Int+Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F6B64F2619E1ED0038F10D /* Int+Operations.swift */; }; + 84F76ED629006A0900D7206C /* ReferendumConvictionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F76ED529006A0900D7206C /* ReferendumConvictionView.swift */; }; + 84F76ED829006BC400D7206C /* DiscreteGradientSlider+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F76ED729006BC400D7206C /* DiscreteGradientSlider+Style.swift */; }; 84F77AAA265EE86B00F54885 /* CrowdloanErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F77AA9265EE86B00F54885 /* CrowdloanErrorPresentable.swift */; }; 84F81318265B9E990043FA1D /* CrowdloansOperationFactoryStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F81317265B9E990043FA1D /* CrowdloansOperationFactoryStub.swift */; }; 84F98D8A25E3DD3F0040418E /* StorageCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F98D8925E3DD3F0040418E /* StorageCodingPath.swift */; }; @@ -5001,6 +5003,8 @@ 84F6B6422619A8480038F10D /* SubscanConcreteExtrinsicsData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscanConcreteExtrinsicsData.swift; sourceTree = ""; }; 84F6B6472619A87C0038F10D /* ExtrinsicIndexWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicIndexWrapper.swift; sourceTree = ""; }; 84F6B64F2619E1ED0038F10D /* Int+Operations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int+Operations.swift"; sourceTree = ""; }; + 84F76ED529006A0900D7206C /* ReferendumConvictionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumConvictionView.swift; sourceTree = ""; }; + 84F76ED729006BC400D7206C /* DiscreteGradientSlider+Style.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscreteGradientSlider+Style.swift"; sourceTree = ""; }; 84F77AA9265EE86B00F54885 /* CrowdloanErrorPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanErrorPresentable.swift; sourceTree = ""; }; 84F81317265B9E990043FA1D /* CrowdloansOperationFactoryStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloansOperationFactoryStub.swift; sourceTree = ""; }; 84F98D8925E3DD3F0040418E /* StorageCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageCodingPath.swift; sourceTree = ""; }; @@ -9517,6 +9521,7 @@ 84E90BA028D0B51000529633 /* CheckboxControlView.swift */, 8468119328E6234B00BF54F1 /* RoundedSegmentedControl.swift */, 84E63C1628FFC69A0093534A /* DiscreteGradientSlider.swift */, + 84F76ED729006BC400D7206C /* DiscreteGradientSlider+Style.swift */, ); path = View; sourceTree = ""; @@ -11902,6 +11907,14 @@ path = View; sourceTree = ""; }; + 84F76ED4290069E900D7206C /* View */ = { + isa = PBXGroup; + children = ( + 84F76ED529006A0900D7206C /* ReferendumConvictionView.swift */, + ); + path = View; + sourceTree = ""; + }; 84F77AA8265EE82E00F54885 /* Protocols */ = { isa = PBXGroup; children = ( @@ -12947,6 +12960,7 @@ CEE6BB9D4D5A0E46E857EED4 /* ReferendumVoteSetup */ = { isa = PBXGroup; children = ( + 84F76ED4290069E900D7206C /* View */, 8425D0DE28FE736F003B782A /* Model */, 5159EA2661A6CBE123CCF891 /* ReferendumVoteSetupProtocols.swift */, 55B2C456A80FA66E6F140814 /* ReferendumVoteSetupWireframe.swift */, @@ -15868,6 +15882,7 @@ 845B821F26EF8E8900D25C72 /* ManagedMetaAccountModel.swift in Sources */, 8430AB1226023C9F005B1066 /* PendingBondedState.swift in Sources */, 88421059289BBA8D00306F2C /* CurrencyViewFactory.swift in Sources */, + 84F76ED829006BC400D7206C /* DiscreteGradientSlider+Style.swift in Sources */, 841E6AFE25EC12DE0007DDFE /* SelectedValidatorInfo.swift in Sources */, F4E17FC52721814D00FE36D3 /* MoonbeamVerifiedResponse.swift in Sources */, 8499FECC27BF8F4A00712589 /* NftModelMapper.swift in Sources */, @@ -16617,6 +16632,7 @@ 41FA237A4AA56AC99322A040 /* ParitySignerAddConfirmPresenter.swift in Sources */, 663DB041307C59E939BF0BE2 /* ParitySignerAddConfirmInteractor.swift in Sources */, 13CF38563E1849EAF1B4E4B6 /* ParitySignerAddConfirmViewFactory.swift in Sources */, + 84F76ED629006A0900D7206C /* ReferendumConvictionView.swift in Sources */, 9979A61C1677B7B1D44E58B4 /* ParitySignerTxQrProtocols.swift in Sources */, 535E9CD08FCA2DA52D37A134 /* ParitySignerTxQrWireframe.swift in Sources */, 95AF91994555227D52FCDA24 /* ParitySignerTxQrPresenter.swift in Sources */, diff --git a/novawallet/Assets.xcassets/colorSliderOverlay.colorset/Contents.json b/novawallet/Assets.xcassets/colorSliderOverlay.colorset/Contents.json new file mode 100644 index 0000000000..232e3744cf --- /dev/null +++ b/novawallet/Assets.xcassets/colorSliderOverlay.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0x3A", + "green" : "0x3A", + "red" : "0x3A" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/iconSliderThumb.imageset/Contents.json b/novawallet/Assets.xcassets/iconSliderThumb.imageset/Contents.json new file mode 100644 index 0000000000..85d874050c --- /dev/null +++ b/novawallet/Assets.xcassets/iconSliderThumb.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "iconSliderThumb.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/iconSliderThumb.imageset/iconSliderThumb.pdf b/novawallet/Assets.xcassets/iconSliderThumb.imageset/iconSliderThumb.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5765cca0b42499ddffcacbaef8f9e67363f2e9ca GIT binary patch literal 9430 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 C3k%W! literal 0 HcmV?d00001 diff --git a/novawallet/Common/View/DiscreteGradientSlider+Style.swift b/novawallet/Common/View/DiscreteGradientSlider+Style.swift new file mode 100644 index 0000000000..4a682d8a2a --- /dev/null +++ b/novawallet/Common/View/DiscreteGradientSlider+Style.swift @@ -0,0 +1,33 @@ +import UIKit + +extension DiscreteGradientSlider { + func applyConvictionDefaultStyle() { + thumbImageView.image = R.image.iconSliderThumb() + trackOverlayView.fillColor = R.color.colorSliderOverlay()! + verticalSpacing = 5.0 + dotColor = R.color.colorBlack48()! + numberOfValues = 7 + titles = ["0.1x", "1x", "2x", "3x", "4x", "5x", "6x"] + titleFont = .caption1 + + applyConvictionActiveStyle() + } + + func applyConvictionActiveStyle() { + colors = [ + UIColor(hex: "#1DE4FF")!, + UIColor(hex: "#1AD1FF")!, + UIColor(hex: "#1EB3FF")!, + UIColor(hex: "#2194FF")!, + UIColor(hex: "#7471FF")!, + UIColor(hex: "#DF00FF")!, + UIColor(hex: "#FF0087")! + ] + } + + func applyConvictionInactiveStyle() { + colors = [ + R.color.colorWhite32()! + ] + } +} diff --git a/novawallet/Common/View/DiscreteGradientSlider.swift b/novawallet/Common/View/DiscreteGradientSlider.swift index 3a45f4c776..e8a28a7c45 100644 --- a/novawallet/Common/View/DiscreteGradientSlider.swift +++ b/novawallet/Common/View/DiscreteGradientSlider.swift @@ -2,20 +2,76 @@ import UIKit import SoraUI class DiscreteGradientSlider: UIControl { - let thumbImageView: UIImageView = UIImageView() - let trackBackgroundView: MultigradientView = MultigradientView() - let trackOverlayView: RoundedView = RoundedView() + let thumbImageView = UIImageView() + let trackBackgroundView: MultigradientView = .create { view in + view.startPoint = CGPoint(x: 0.0, y: 0.5) + view.endPoint = CGPoint(x: 1.0, y: 0.5) + } + + let trackOverlayView: RoundedView = .create { view in + view.applyCellBackgroundStyle() + } - private(set) var value: UInt = 0 - private(set) var numberOfValues: UInt = 3 + var value: UInt = 0 { + didSet { + setNeedsLayout() + } + } - var trackHeight: CGFloat = 8.0 { + var numberOfValues: UInt = 3 { didSet { + reconfigureSteps() setNeedsLayout() } } - var contentInsets: UIEdgeInsets = UIEdgeInsets(top: 16.0, left: 0.0, bottom: 16.0, right: 0.0) { + var trackHeight: CGFloat = 10.0 { + didSet { + trackBackgroundView.cornerRadius = trackHeight / 2.0 + trackOverlayView.cornerRadius = trackHeight / 2.0 + + invalidateIntrinsicContentSize() + setNeedsLayout() + } + } + + var dotRadius: CGFloat = 3.0 { + didSet { + setNeedsLayout() + } + } + + var dotColor: UIColor = R.color.colorDarkGray()! { + didSet { + updateDotsStyle(dots) + } + } + + var verticalSpacing: CGFloat = 14 { + didSet { + invalidateIntrinsicContentSize() + setNeedsLayout() + } + } + + var sliderInset: CGFloat = 16 { + didSet { + setNeedsLayout() + } + } + + var dragTriggerOffset: CGFloat = 5.0 + + var titleFont: UIFont? { + didSet { + updateTitlesStyle() + + invalidateIntrinsicContentSize() + setNeedsLayout() + } + } + + var contentInsets = UIEdgeInsets(top: 16.0, left: 0.0, bottom: 16.0, right: 0.0) { didSet { invalidateIntrinsicContentSize() setNeedsLayout() @@ -23,16 +79,45 @@ class DiscreteGradientSlider: UIControl { } override var intrinsicContentSize: CGSize { - let contentHeight = max(thumbImageView.intrinsicContentSize.height, trackHeight) - let height = contentHeight + contentInsets.top + contentInsets.bottom + let sliderHeight = max(thumbImageView.intrinsicContentSize.height, trackHeight) + + let labelsHeight = titleLabels.map(\.intrinsicContentSize.height).max() ?? 0 + + let height = labelsHeight + verticalSpacing + sliderHeight + contentInsets.top + contentInsets.bottom return CGSize(width: UIView.noIntrinsicMetric, height: height) } var colors: [UIColor] { - trackBackgroundView.colors + get { + trackBackgroundView.colors + } + + set { + trackBackgroundView.colors = newValue + + updateTitlesStyle() + } + } + + var titles: [String] { + get { + titleLabels.map { $0.text ?? "" } + } + + set { + guard newValue.count == titleLabels.count else { + return + } + + zip(newValue, titleLabels).forEach { $0.1.text = $0.0 } + + invalidateIntrinsicContentSize() + setNeedsLayout() + } } private var dots: [RoundedView] = [] + private var titleLabels: [UILabel] = [] override init(frame: CGRect) { super.init(frame: frame) @@ -42,35 +127,197 @@ class DiscreteGradientSlider: UIControl { configure() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } private func configure() { + trackOverlayView.isUserInteractionEnabled = false + trackBackgroundView.isUserInteractionEnabled = false + + trackBackgroundView.cornerRadius = trackHeight / 2.0 + trackOverlayView.cornerRadius = trackHeight / 2.0 + addSubview(trackBackgroundView) addSubview(trackOverlayView) addSubview(thumbImageView) + + reconfigureSteps() } - private func updateThumbPosition() { - guard numberOfValues > 1 else { - return + private func reconfigureSteps() { + if dots.count > numberOfValues { + let dropCount = dots.count - Int(numberOfValues) + + let removingDots = Array(dots.suffix(dropCount)) + removingDots.forEach { $0.removeFromSuperview() } + + dots = dots.dropLast(dropCount) + + let removingTitles = Array(titleLabels.suffix(dropCount)) + removingTitles.forEach { $0.removeFromSuperview() } + + titleLabels = titleLabels.dropLast(dropCount) + + } else if dots.count < numberOfValues { + let addCount = Int(numberOfValues) - dots.count + + let newDots: [RoundedView] = (0 ..< addCount).map { _ in + let dotView = RoundedView() + dotView.shadowOpacity = 0.0 + return dotView + } + + newDots.forEach { insertSubview($0, aboveSubview: trackOverlayView) } + + updateDotsStyle(newDots) + + dots.append(contentsOf: newDots) + + let newTitleLabels = (0 ..< addCount).map { _ in UILabel() } + + newTitleLabels.forEach { insertSubview($0, aboveSubview: trackOverlayView) } + + titleLabels.append(contentsOf: newTitleLabels) + + updateTitlesStyle() + } + } + + private func updateDotsStyle(_ dots: [RoundedView]) { + dots.forEach { dot in + dot.fillColor = dotColor + } + } + + private func updateTitlesStyle() { + titleLabels.enumerated().forEach { index, label in + if index < colors.count { + label.textColor = colors[index] + } else { + label.textColor = colors.last + } + + label.font = titleFont } + } - let step = bounds.height / CGFloat(numberOfValues - 1) - let positionX = CGFloat(value) * step + private func calculateStep() -> CGFloat { + let availableWidth = bounds.width - contentInsets.left - contentInsets.right - + 2 * (sliderInset + dotRadius) + + if availableWidth > 0, numberOfValues > 1 { + return availableWidth / CGFloat(numberOfValues - 1) + } else { + return 0 + } + } + + private func stepPositionX(for value: UInt) -> CGFloat { + let step = calculateStep() + return contentInsets.left + sliderInset + dotRadius + CGFloat(value) * step + } + + private func layoutDynamicViews() { + let positionX = stepPositionX(for: value) let size = thumbImageView.intrinsicContentSize thumbImageView.frame = CGRect( x: positionX - size.width / 2.0, - y: bounds.midY - size.height / 2.0, + y: trackBackgroundView.frame.midY - size.height / 2.0, width: size.width, height: size.height ) + + let overlaySize = CGSize(width: bounds.width - positionX, height: trackHeight) + trackOverlayView.frame = CGRect( + x: positionX, + y: trackBackgroundView.frame.midY - overlaySize.height / 2.0, + width: overlaySize.width, + height: overlaySize.height + ) + } + + private func layoutDots() { + (0 ..< numberOfValues).forEach { value in + let positionX = stepPositionX(for: value) + + let dotView = dots[Int(value)] + dotView.frame = CGRect( + x: positionX - dotRadius, + y: trackBackgroundView.frame.midY - dotRadius, + width: 2 * dotRadius, + height: 2 * dotRadius + ) + + dotView.cornerRadius = dotRadius + } + } + + private func layoutTitleLabels() { + (0 ..< numberOfValues).forEach { value in + let positionX = stepPositionX(for: value) + + let titleLabel = titleLabels[Int(value)] + let size = titleLabel.intrinsicContentSize + + titleLabel.frame = CGRect( + x: positionX - size.width / 2.0, + y: contentInsets.top, + width: size.width, + height: size.height + ) + } } override func layoutSubviews() { super.layoutSubviews() + + let sliderHeight = max(trackHeight, thumbImageView.intrinsicContentSize.height) + + trackBackgroundView.frame = CGRect( + x: bounds.minX + contentInsets.left, + y: bounds.maxY - contentInsets.bottom - sliderHeight / 2.0 - trackHeight / 2.0, + width: bounds.width - contentInsets.left - contentInsets.right, + height: trackHeight + ) + + layoutDynamicViews() + layoutDots() + layoutTitleLabels() + } + + private func updateValue(for location: CGFloat) { + let step = calculateStep() + + guard step > 0 else { + return + } + + let diff = round((location - stepPositionX(for: 0)) / step) + + value = min(numberOfValues - 1, UInt(max(0, Int(diff)))) + } + + override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { + super.beginTracking(touch, with: event) + + let locationX = touch.location(in: self).x + + updateValue(for: locationX) + + return true + } + + override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { + super.beginTracking(touch, with: event) + + let locationX = touch.location(in: self).x + + updateValue(for: locationX) + + return true } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index ab2055d64d..f7c308c532 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -1,5 +1,5 @@ import BigInt -protocol ReferendumVoteSetupViewProtocol: AnyObject {} +protocol ReferendumVoteSetupViewProtocol: ControllerBackedProtocol {} protocol ReferendumVoteSetupPresenterProtocol: AnyObject { func setup() diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift index ec0198a1e1..3d573690d3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -31,9 +31,7 @@ final class ReferendumVoteSetupViewController: UIViewController { presenter.setup() } - private func setupLocalization() { - - } + private func setupLocalization() {} } extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index 43aca0b07b..b8a3453e7b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -1,6 +1,7 @@ import Foundation import SubstrateSdk import RobinHood +import SoraFoundation struct ReferendumVoteSetupViewFactory { static func createView( @@ -9,7 +10,11 @@ struct ReferendumVoteSetupViewFactory { ) -> ReferendumVoteSetupViewProtocol? { guard let currencyManager = CurrencyManager.shared, - let interactor = createInteractor(for: state, referendum: referendum, currencyManager: currencyManager) else { + let interactor = createInteractor( + for: state, + referendum: referendum, + currencyManager: currencyManager + ) else { return nil } @@ -17,7 +22,10 @@ struct ReferendumVoteSetupViewFactory { let presenter = ReferendumVoteSetupPresenter(interactor: interactor, wireframe: wireframe) - let view = ReferendumVoteSetupViewController(presenter: presenter) + let view = ReferendumVoteSetupViewController( + presenter: presenter, + localizationManager: LocalizationManager.shared + ) presenter.view = view interactor.presenter = presenter @@ -32,7 +40,9 @@ struct ReferendumVoteSetupViewFactory { ) -> ReferendumVoteSetupInteractor? { guard let chain = state.settings.value, - let selectedAccount = SelectedWalletSettings.shared.value?.fetchMetaChainAccount(for: chain.accountRequest()), + let selectedAccount = SelectedWalletSettings.shared.value?.fetchMetaChainAccount( + for: chain.accountRequest() + ), let subscriptionFactory = state.subscriptionFactory, let blockTimeService = state.blockTimeService else { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index 35c9cc2679..736d9da470 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -33,6 +33,8 @@ final class ReferendumVoteSetupViewLayout: UIView { let amountInputView = NewAmountInputView() + let convictionView = ReferendumConvictionView() + let lockedAmountView = ReferendumVoteSetupViewLayout.createMultiValueView() let lockedPeriodView = ReferendumVoteSetupViewLayout.createMultiValueView() @@ -89,12 +91,15 @@ final class ReferendumVoteSetupViewLayout: UIView { make.height.equalTo(34.0) } - containerView.stackView.addArrangedSubview(amountInputView) amountInputView.snp.makeConstraints { make in make.height.equalTo(64) } - containerView.stackView.setCustomSpacing(16.0, after: amountInputView) + containerView.stackView.setCustomSpacing(12.0, after: amountInputView) + + containerView.stackView.addArrangedSubview(convictionView) + + containerView.stackView.setCustomSpacing(16.0, after: convictionView) containerView.stackView.addArrangedSubview(lockedAmountView) containerView.stackView.addArrangedSubview(lockedPeriodView) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift new file mode 100644 index 0000000000..46d459144c --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift @@ -0,0 +1,68 @@ +import Foundation +import UIKit +import SoraUI + +final class ReferendumConvictionView: UIView { + let backgroundView: RoundedView = .create { view in + view.applyCellBackgroundStyle() + view.cornerRadius = 12.0 + } + + let titleLabel: UILabel = .create { view in + view.font = .regularFootnote + view.textColor = R.color.colorTransparentText() + } + + let slider: DiscreteGradientSlider = .create { view in + view.applyConvictionDefaultStyle() + } + + let separatorView: UIView = .create { view in + view.backgroundColor = R.color.colorWhite8() + } + + let votesView: UILabel = .create { view in + view.textColor = R.color.colorWhite() + view.font = .boldTitle2 + } + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + addSubview(backgroundView) + + backgroundView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + let stackView = UIView.vStack([ + titleLabel, + slider, + separatorView, + votesView + ]) + + stackView.spacing = 0 + stackView.setCustomSpacing(12.0, after: titleLabel) + stackView.setCustomSpacing(12.0, after: separatorView) + + backgroundView.addSubview(stackView) + + stackView.snp.makeConstraints { make in + make.edges.equalToSuperview().inset(16.0) + } + + separatorView.snp.makeConstraints { make in + make.height.equalTo(1) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index 979a8d2eb5..82fe6f7832 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -32,7 +32,7 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { } func showReferendumDetails(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) { - guard let detailsView = ReferendumDetailsViewFactory.createView(for: referendum, state: state) else { + guard let detailsView = ReferendumVoteSetupViewFactory.createView(for: state, referendum: referendum.index) else { return } From b4d354d837ac60a60a65e87a590da0d94d242ce2 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 20 Oct 2022 02:00:10 +0300 Subject: [PATCH 064/229] added dot view --- novawallet.xcodeproj/project.pbxproj | 8 ++ .../ReferendumDetailsViewController.swift | 5 +- .../View/Rows/VotingDetailsRow.swift | 1 + .../View/Timeline/DotsView.swift | 109 ++++++++++++++++++ .../Timeline/ReferendumTimelineView.swift | 51 ++++---- .../View/Timeline/UIView+frame.swift | 18 +++ .../ReferendumDetails/View/VoteRowView.swift | 2 +- 7 files changed, 171 insertions(+), 23 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/UIView+frame.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 59cfbeb524..d535be7c5a 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2197,6 +2197,8 @@ 880855F828D09DA8004255E7 /* CrowdloanContributionDataMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855F728D09DA8004255E7 /* CrowdloanContributionDataMapper.swift */; }; 880855FA28D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855F928D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift */; }; 880855FC28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */; }; + 882808C829009CA500AE8089 /* DotsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C729009CA500AE8089 /* DotsView.swift */; }; + 882808CA29009CDC00AE8089 /* UIView+frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C929009CDC00AE8089 /* UIView+frame.swift */; }; 8828C05828B4A67000555CB6 /* Prism.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8828C05728B4A67000555CB6 /* Prism.swift */; }; 8828C05A28B4A6A800555CB6 /* Samples.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8828C05928B4A6A800555CB6 /* Samples.swift */; }; 8828F4F328AD2734009E0B7C /* CrowdloansCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8828F4F228AD2734009E0B7C /* CrowdloansCalculator.swift */; }; @@ -5084,6 +5086,8 @@ 880855F928D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionLocalSubscriptionFactory.swift; sourceTree = ""; }; 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloansLocalStorageSubscriber.swift; sourceTree = ""; }; 8821119C96944A0E3526E93A /* StakingRedeemViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRedeemViewFactory.swift; sourceTree = ""; }; + 882808C729009CA500AE8089 /* DotsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotsView.swift; sourceTree = ""; }; + 882808C929009CDC00AE8089 /* UIView+frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+frame.swift"; sourceTree = ""; }; 8828C05728B4A67000555CB6 /* Prism.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Prism.swift; sourceTree = ""; }; 8828C05928B4A6A800555CB6 /* Samples.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Samples.swift; sourceTree = ""; }; 8828F4F228AD2734009E0B7C /* CrowdloansCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloansCalculator.swift; sourceTree = ""; }; @@ -12095,6 +12099,8 @@ children = ( 88A95FA528F8664100BE26F3 /* ReferendumTimelineView.swift */, 887A717B28FEF03E00B13C7E /* BaselinedView.swift */, + 882808C729009CA500AE8089 /* DotsView.swift */, + 882808C929009CDC00AE8089 /* UIView+frame.swift */, ); path = Timeline; sourceTree = ""; @@ -14956,6 +14962,7 @@ F471897B26C29A78006487AD /* AnalyticsValidatorsPageSelector.swift in Sources */, 8482F63128101FB10006C3A0 /* DAppEthereumSignBytesInteractor.swift in Sources */, 8487583527F06AF300495306 /* QRScannerProtocols.swift in Sources */, + 882808C829009CA500AE8089 /* DotsView.swift in Sources */, 8860F3E8289D7CF400C0BF86 /* Atomic.swift in Sources */, 8499FECF27BFA25100712589 /* NftType.swift in Sources */, F40966C226B297D6008CD244 /* AnalyticsPeriod.swift in Sources */, @@ -16674,6 +16681,7 @@ 99A045F3C6403FB48B39971D /* LedgerWalletConfirmProtocols.swift in Sources */, DCE9FE8A75C2FE7B5CB92CC2 /* LedgerWalletConfirmWireframe.swift in Sources */, 106CC4BFC48B6BFFF31434A9 /* LedgerWalletConfirmPresenter.swift in Sources */, + 882808CA29009CDC00AE8089 /* UIView+frame.swift in Sources */, 4541F886953E046C16E42997 /* LedgerWalletConfirmInteractor.swift in Sources */, 2A652719FB31E3C8FF36F46A /* LedgerWalletConfirmViewFactory.swift in Sources */, 95EBC71EAE906B0DFA758AB8 /* LedgerTxConfirmProtocols.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 785cf2c3de..71fc97fd29 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -98,8 +98,9 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { ) set(timelineModel: .init(title: "Timeline", statuses: [ - .init(title: "Created", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), - .init(title: "Created", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) + .init(title: "One", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), + .init(title: "Two", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), + .init(title: "Three", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) ])) rootView.fullDetailsView.bind(title: "Full details") diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift index a3619c562d..9cde279050 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift @@ -7,6 +7,7 @@ final class VotingDetailsRow: RowView { super.init(frame: frame) contentView = referendumVotingStatusDetailsView + contentInsets = .zero backgroundView = TriangularedBlurView() backgroundColor = .clear } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift new file mode 100644 index 0000000000..c665923071 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift @@ -0,0 +1,109 @@ +import UIKit + +final class DotsView: UIView { + struct Model { + let view: BaselinedView + let isFinite: Bool + } + + var points: [Model] = [] + private var style: Style = .defaultStyle + + override init(frame: CGRect) { + super.init(frame: frame) + + backgroundColor = .clear + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func draw(_ rect: CGRect) { + super.draw(rect) + drawDots() + } + + private func drawDots() { + guard let context = UIGraphicsGetCurrentContext(), + let superview = superview else { + return + } + setup(context: context) + let dotX = frame.midX + + for index in 0 ..< points.count { + let dotY = points[index].view.firstBaseline.frame(in: superview).midY + let firstDot = createCircle(with: .init(x: dotX, y: dotY)) + firstDot.move(to: .init(x: dotX, y: dotY + style.dotRadius + style.space)) + + let nextDotY: CGFloat + if index == points.count - 1 { + firstDot.stroke() + firstDot.fill() + + guard !points[index].isFinite else { + continue + } + let dottedLinePath = UIBezierPath() + nextDotY = frame.maxY + dottedLinePath.setLineDash(style.pattern, count: style.pattern.count, phase: 0) + dottedLinePath.addLine(to: .init(x: dotX, y: nextDotY - style.dotRadius - style.space)) + dottedLinePath.stroke() + dottedLinePath.fill() + } else { + nextDotY = points[index + 1].view.firstBaseline.frame(in: superview).midY + firstDot.addLine(to: .init(x: dotX, y: nextDotY - style.dotRadius - style.space)) + firstDot.stroke() + firstDot.fill() + + let secondDot = createCircle(with: .init(x: dotX, y: nextDotY)) + secondDot.stroke() + secondDot.fill() + } + } + } + + private func createCircle(with center: CGPoint) -> UIBezierPath { + UIBezierPath( + arcCenter: center, + radius: style.dotRadius, + startAngle: 0, + endAngle: 2 * .pi, + clockwise: true + ) + } + + private func setup(context: CGContext) { + context.setStrokeColor(style.color.cgColor) + context.setFillColor(style.color.cgColor) + context.setLineWidth(style.lineWidth) + } +} + +extension DotsView { + struct Style { + let lineWidth: CGFloat + let color: UIColor + let dotRadius: CGFloat + let space: CGFloat + let pattern: [CGFloat] + } + + func apply(style: Style) { + self.style = style + invalidateIntrinsicContentSize() + setNeedsDisplay() + } +} + +extension DotsView.Style { + static let defaultStyle = DotsView.Style( + lineWidth: 1, + color: R.color.colorNovaBlue()!, + dotRadius: 6, + space: 6, + pattern: [2, 3] + ) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift index cd6ab3845c..8e1ce05387 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift @@ -2,8 +2,10 @@ import UIKit import SoraUI final class ReferendumTimelineView: UIView { - private(set) var statusesView: [BaselinedView] = [] - var content = UIStackView() + let dotsView = DotsView() + let statusesContentView: UIStackView = .create { + $0.axis = .vertical + } override init(frame: CGRect) { super.init(frame: frame) @@ -17,29 +19,36 @@ final class ReferendumTimelineView: UIView { } private func setupLayout() { - content = UIView.vStack(statusesView) - addSubview(content) - content.snp.makeConstraints { - $0.edges.equalToSuperview().inset(UIEdgeInsets(top: 0, left: 44, bottom: 0, right: 0)) + addSubview(dotsView) + addSubview(statusesContentView) + + dotsView.snp.makeConstraints { + $0.top.bottom.leading.equalToSuperview() + $0.width.equalTo(12) + } + + statusesContentView.spacing = 12 + statusesContentView.snp.makeConstraints { + $0.top.bottom.trailing.equalToSuperview() + $0.leading.equalTo(dotsView.snp.trailing).inset(16) } } private func updateStatuses(model: Model) { - layoutIfNeeded() - statusesView = createStatusesView(from: model) - content.arrangedSubviews.forEach { - content.removeArrangedSubview($0) + let statusViews = statusViews(from: model) + statusesContentView.arrangedSubviews.forEach { + statusesContentView.removeArrangedSubview($0) } - content.addArrangedSubview(UIView.vStack(statusesView)) - statusesView.forEach { - $0.snp.makeConstraints { make in - make.height.equalTo(44) - } + statusViews.forEach { + statusesContentView.addArrangedSubview($0.view) + } + dotsView.points = statusViews.map { + DotsView.Model(view: $0.view, isFinite: $0.status.isLast) } } - private func createStatusesView(from model: Model) -> [BaselinedView] { - model.statuses.map { status -> BaselinedView in + private func statusViews(from model: Model) -> [(view: BaselinedView, status: Model.Status)] { + model.statuses.map { status in switch status.subtitle { case let .date(date): let view = MultiValueView() @@ -47,17 +56,17 @@ final class ReferendumTimelineView: UIView { view.valueTop.textAlignment = .left view.valueBottom.textAlignment = .left view.valueBottom.text = date - return view + return (view: view, status: status) case let .interval(model): let view = GenericMultiValueView() view.valueTop.text = status.title view.valueTop.textAlignment = .left view.valueBottom.bind(viewModel: model) - return view + return (view: view, status: status) case .none: let label = UILabel() label.text = status.title - return label + return (view: label, status: status) } } } @@ -82,5 +91,7 @@ extension ReferendumTimelineView: BindableView { func bind(viewModel: Model) { updateStatuses(model: viewModel) + dotsView.setNeedsDisplay() + dotsView.setNeedsLayout() } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/UIView+frame.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/UIView+frame.swift new file mode 100644 index 0000000000..ed1826e030 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/UIView+frame.swift @@ -0,0 +1,18 @@ +import UIKit + +extension UIView { + func frame(in targetView: UIView) -> CGRect { + var view = self + var rect = view.frame + + while let superview = view.superview { + if superview == targetView { + return rect + } + rect = view.convert(rect, to: superview) + view = superview + } + + return rect + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift index 611e61d911..a0dd49ca70 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift @@ -14,7 +14,7 @@ final class VoteRowView: UIView { } private var leadingRectangleView: UIView = .create { - $0.layer.cornerRadius = 10 + $0.layer.cornerRadius = 4 } private var trailingImageView = UIImageView() From 4f230c485207ebca229ac5fa701c5ebec6779433 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 20 Oct 2022 02:09:11 +0300 Subject: [PATCH 065/229] fix dotted line --- .../ReferendumDetails/View/Rows/TimelineRow.swift | 2 +- .../ReferendumDetails/View/Timeline/DotsView.swift | 3 ++- .../View/Timeline/ReferendumTimelineView.swift | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift index 24700e39f1..7d1a28da2c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift @@ -8,7 +8,7 @@ final class TimelineRow: RowView { contentView = referendumTimelineView backgroundView = TriangularedBlurView() - contentInsets = .init(top: 16, left: 16, bottom: 20, right: 16) + contentInsets = .init(top: 16, left: 16, bottom: 0, right: 16) backgroundColor = .clear } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift index c665923071..0a6de9d5d9 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift @@ -48,8 +48,9 @@ final class DotsView: UIView { } let dottedLinePath = UIBezierPath() nextDotY = frame.maxY + dottedLinePath.move(to: .init(x: dotX, y: dotY + style.dotRadius + style.space)) dottedLinePath.setLineDash(style.pattern, count: style.pattern.count, phase: 0) - dottedLinePath.addLine(to: .init(x: dotX, y: nextDotY - style.dotRadius - style.space)) + dottedLinePath.addLine(to: .init(x: dotX, y: nextDotY)) dottedLinePath.stroke() dottedLinePath.fill() } else { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift index 8e1ce05387..c70484dc47 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift @@ -24,13 +24,14 @@ final class ReferendumTimelineView: UIView { dotsView.snp.makeConstraints { $0.top.bottom.leading.equalToSuperview() - $0.width.equalTo(12) + $0.width.equalTo(14) } statusesContentView.spacing = 12 statusesContentView.snp.makeConstraints { - $0.top.bottom.trailing.equalToSuperview() - $0.leading.equalTo(dotsView.snp.trailing).inset(16) + $0.top.trailing.equalToSuperview() + $0.bottom.equalToSuperview().inset(20) + $0.leading.equalTo(dotsView.snp.trailing).inset(-16) } } From 7c87c021baacd0c4ff28533515f5125fb9cc7466 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 20 Oct 2022 12:15:53 +0500 Subject: [PATCH 066/229] bind base view model --- .../Common/View/DiscreteGradientSlider.swift | 1 + .../Common/View/GenericMultiValueView.swift | 52 ++++ .../ReferendumVoteInteractor.swift | 2 +- .../ReferendumVoteSetupInteractor.swift | 10 +- .../ReferendumVoteSetupPresenter.swift | 269 +++++++++++++++++- .../ReferendumVoteSetupProtocols.swift | 13 +- .../ReferendumVoteSetupViewController.swift | 73 ++++- .../ReferendumVoteSetupViewFactory.swift | 41 ++- .../ReferendumVoteSetupViewLayout.swift | 78 ++++- novawallet/en.lproj/Localizable.strings | 6 + novawallet/ru.lproj/Localizable.strings | 6 + 11 files changed, 510 insertions(+), 41 deletions(-) diff --git a/novawallet/Common/View/DiscreteGradientSlider.swift b/novawallet/Common/View/DiscreteGradientSlider.swift index e8a28a7c45..f6315c7acd 100644 --- a/novawallet/Common/View/DiscreteGradientSlider.swift +++ b/novawallet/Common/View/DiscreteGradientSlider.swift @@ -166,6 +166,7 @@ class DiscreteGradientSlider: UIControl { let newDots: [RoundedView] = (0 ..< addCount).map { _ in let dotView = RoundedView() dotView.shadowOpacity = 0.0 + dotView.isUserInteractionEnabled = false return dotView } diff --git a/novawallet/Common/View/GenericMultiValueView.swift b/novawallet/Common/View/GenericMultiValueView.swift index 31cab5df85..b4f38b6ee4 100644 --- a/novawallet/Common/View/GenericMultiValueView.swift +++ b/novawallet/Common/View/GenericMultiValueView.swift @@ -1,6 +1,58 @@ import UIKit import SoraUI +class GenericPairValueView: UIView { + let fView = FView() + let sView = SView() + + var spacing: CGFloat { + get { + stackView.spacing + } + + set { + stackView.spacing = newValue + } + } + + let stackView: UIStackView = { + let view = UIStackView() + view.axis = .vertical + return view + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setVerticalAndSpacing(_ spacing: CGFloat) { + stackView.axis = .vertical + stackView.spacing = spacing + } + + func setHorizontalAndSpacing(_ spacing: CGFloat) { + stackView.axis = .horizontal + stackView.spacing = spacing + } + + private func setupLayout() { + addSubview(stackView) + stackView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + stackView.addArrangedSubview(fView) + stackView.addArrangedSubview(sView) + } +} + class GenericMultiValueView: UIView { let valueTop: UILabel = { let label = UILabel() diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift index 932a376072..67d60ebc47 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift @@ -3,7 +3,7 @@ import RobinHood import BigInt class ReferendumVoteInteractor { - private weak var basePresenter: ReferendumVoteInteractorOutputProtocol? + weak var basePresenter: ReferendumVoteInteractorOutputProtocol? let referendumIndex: ReferendumIdLocal let selectedAccount: MetaChainAccountResponse diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift index d2eccf6fee..ecd60fb2c7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift @@ -3,7 +3,15 @@ import SubstrateSdk import RobinHood final class ReferendumVoteSetupInteractor: ReferendumVoteInteractor, AnyCancellableCleaning { - weak var presenter: ReferendumVoteSetupInteractorOutputProtocol? + weak var presenter: ReferendumVoteSetupInteractorOutputProtocol? { + get { + basePresenter as? ReferendumVoteSetupInteractorOutputProtocol + } + + set { + basePresenter = newValue + } + } let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol let blockTimeService: BlockTimeEstimationServiceProtocol diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 53009eda2f..706f27f2d7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -1,44 +1,291 @@ import Foundation import BigInt +import SoraFoundation final class ReferendumVoteSetupPresenter { weak var view: ReferendumVoteSetupViewProtocol? let wireframe: ReferendumVoteSetupWireframeProtocol let interactor: ReferendumVoteSetupInteractorInputProtocol + let chain: ChainModel + let referendumIndex: ReferendumIdLocal + + let balanceViewModelFactory: BalanceViewModelFactoryProtocol + let referendumFormatter: LocalizableResource + let chainAssetViewModelFactory: ChainAssetViewModelFactoryProtocol + let logger: LoggerProtocol + + private var assetBalance: AssetBalance? + private var fee: BigUInt? + private var priceData: PriceData? + private var votesResult: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]>? + private var blockNumber: BlockNumber? + private var blockTime: BlockTime? + private var referendum: ReferendumLocal? + private var lockDiff: GovernanceLockStateDiff? + + var inputResult: AmountInputResult? + init( + chain: ChainModel, + referendumIndex: ReferendumIdLocal, + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + referendumFormatter: LocalizableResource, + chainAssetViewModelFactory: ChainAssetViewModelFactoryProtocol, interactor: ReferendumVoteSetupInteractorInputProtocol, - wireframe: ReferendumVoteSetupWireframeProtocol + wireframe: ReferendumVoteSetupWireframeProtocol, + localizationManager: LocalizationManagerProtocol, + logger: LoggerProtocol ) { + self.chain = chain + self.referendumIndex = referendumIndex + self.balanceViewModelFactory = balanceViewModelFactory + self.chainAssetViewModelFactory = chainAssetViewModelFactory + self.referendumFormatter = referendumFormatter self.interactor = interactor self.wireframe = wireframe + self.logger = logger + + self.localizationManager = localizationManager + } + + private func balanceMinusFee() -> Decimal { + let balanceValue = assetBalance?.freeInPlank ?? 0 + let feeValue = fee ?? 0 + + guard + let precision = chain.utilityAsset()?.displayInfo.assetPrecision, + let balance = Decimal.fromSubstrateAmount(balanceValue, precision: precision), + let fee = Decimal.fromSubstrateAmount(feeValue, precision: precision) else { + return 0 + } + + return balance - fee + } + + private func updateFeeView() { + let optAssetInfo = chain.utilityAssets().first?.displayInfo + if let fee = fee, let assetInfo = optAssetInfo { + let feeDecimal = Decimal.fromSubstrateAmount( + fee, + precision: assetInfo.assetPrecision + ) ?? 0.0 + + let viewModel = balanceViewModelFactory.balanceFromPrice( + feeDecimal, + priceData: priceData + ).value(for: selectedLocale) + + view?.didReceiveFee(viewModel: viewModel) + } else { + view?.didReceiveFee(viewModel: nil) + } + } + + private func updateAvailableBalanceView() { + if let assetBalance = assetBalance { + let precision = chain.utilityAsset()?.displayInfo.assetPrecision ?? 0 + let balanceDecimal = Decimal.fromSubstrateAmount( + assetBalance.freeInPlank, + precision: precision + ) ?? 0 + + let viewModel = balanceViewModelFactory.balanceFromPrice( + balanceDecimal, + priceData: nil + ).value(for: selectedLocale).amount + + view?.didReceiveBalance(viewModel: viewModel) + } + } + + private func updateChainAssetViewModel() { + guard let asset = chain.utilityAsset() else { + return + } + + let chainAsset = ChainAsset(chain: chain, asset: asset) + let viewModel = chainAssetViewModelFactory.createViewModel(from: chainAsset) + view?.didReceiveInputChainAsset(viewModel: viewModel) + } + + private func updateAmountPriceView() { + if chain.utilityAsset()?.priceId != nil { + let inputAmount = inputResult?.absoluteValue(from: balanceMinusFee()) ?? 0 + + let priceData = priceData ?? PriceData.zero() + + let price = balanceViewModelFactory.priceFromAmount( + inputAmount, + priceData: priceData + ).value(for: selectedLocale) + + view?.didReceiveAmountInputPrice(viewModel: price) + } else { + view?.didReceiveAmountInputPrice(viewModel: nil) + } + } + + private func provideReferendumIndex() { + let referendumString = referendumFormatter.value(for: selectedLocale).string(from: referendumIndex as NSNumber) + view?.didReceive(referendumNumber: referendumString ?? "") + } + + private func provideAmountInputViewModelIfRate() { + guard case .rate = inputResult else { + return + } + + provideAmountInputViewModel() + } + + private func provideAmountInputViewModel() { + let inputAmount = inputResult?.absoluteValue(from: balanceMinusFee()) + + let viewModel = balanceViewModelFactory.createBalanceInputViewModel( + inputAmount + ).value(for: selectedLocale) + + view?.didReceiveAmount(inputViewModel: viewModel) + } + + private func updateView() { + provideReferendumIndex() + updateAvailableBalanceView() + provideAmountInputViewModel() + updateChainAssetViewModel() + updateAmountPriceView() + updateFeeView() + } + + private func deriveNewVote() -> ReferendumNewVote? { + let amount = inputResult?.absoluteValue(from: balanceMinusFee()) ?? 0 + + guard + let precision = chain.utilityAsset()?.displayInfo.assetPrecision, + let amountInPlank = amount.toSubstrateAmount(precision: precision) else { + return nil + } + + let voteAction = ReferendumVoteAction( + amount: amountInPlank, + conviction: .none, + isAye: true + ) + + return ReferendumNewVote(index: referendumIndex, voteAction: voteAction) + } + + private func refreshFee() { + guard let newVote = deriveNewVote() else { + return + } + + interactor.estimateFee(for: newVote.voteAction) + } + + private func refereshLockDiff() { + guard let votesResult = votesResult, let newVote = deriveNewVote() else { + return + } + + interactor.refreshLockDiff(for: votesResult.value ?? [:], newVote: newVote, blockHash: votesResult.blockHash) } } extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { - func setup() {} + func setup() { + updateView() + + interactor.setup() + } } extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProtocol { - func didReceiveLockStateDiff(_: GovernanceLockStateDiff) {} + func didReceiveLockStateDiff(_ diff: GovernanceLockStateDiff) { + lockDiff = diff + } func didReceiveAccountVotes( - _: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]> - ) {} + _ votesResult: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]> + ) { + self.votesResult = votesResult + + refereshLockDiff() + } func didReceiveBlockNumber(_: BlockNumber) {} func didReceiveBlockTime(_: BlockTime) {} - func didReceiveError(_: ReferendumVoteSetupInteractorError) {} + func didReceiveError(_ error: ReferendumVoteSetupInteractorError) { + logger.error("Did receive setup error: \(error)") - func didReceiveAssetBalance(_: AssetBalance?) {} + switch error { + case .accountVotesFailed, .blockNumberSubscriptionFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + case .blockTimeFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refreshBlockTime() + } + case .stateDiffFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.refereshLockDiff() + } + } + } - func didReceivePrice(_: PriceData?) {} + func didReceiveAssetBalance(_ assetBalance: AssetBalance?) { + self.assetBalance = assetBalance - func didReceiveVotingReferendum(_: ReferendumLocal) {} + updateAvailableBalanceView() + updateAmountPriceView() + provideAmountInputViewModelIfRate() + + refreshFee() + } - func didReceiveFee(_: BigUInt) {} + func didReceivePrice(_ price: PriceData?) { + priceData = price + + updateAmountPriceView() + updateFeeView() + } + + func didReceiveVotingReferendum(_ referendum: ReferendumLocal) { + self.referendum = referendum + } - func didReceiveBaseError(_: ReferendumVoteInteractorError) {} + func didReceiveFee(_ fee: BigUInt) { + self.fee = fee + + updateFeeView() + updateAmountPriceView() + provideAmountInputViewModelIfRate() + } + + func didReceiveBaseError(_ error: ReferendumVoteInteractorError) { + logger.error("Did receive base error: \(error)") + + switch error { + case .assetBalanceFailed, .priceFailed, .votingReferendumFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + case .feeFailed: + wireframe.presentFeeStatus(on: view, locale: selectedLocale) { [weak self] in + self?.refreshFee() + } + } + } +} + +extension ReferendumVoteSetupPresenter: Localizable { + func applyLocalization() { + if let view = view, view.isSetup { + updateView() + } + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index f7c308c532..1f1cbe7933 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -1,5 +1,14 @@ import BigInt -protocol ReferendumVoteSetupViewProtocol: ControllerBackedProtocol {} +import CommonWallet + +protocol ReferendumVoteSetupViewProtocol: ControllerBackedProtocol { + func didReceive(referendumNumber: String) + func didReceiveBalance(viewModel: String) + func didReceiveInputChainAsset(viewModel: ChainAssetViewModel) + func didReceiveAmount(inputViewModel: AmountInputViewModelProtocol) + func didReceiveFee(viewModel: BalanceViewModelProtocol?) + func didReceiveAmountInputPrice(viewModel: String?) +} protocol ReferendumVoteSetupPresenterProtocol: AnyObject { func setup() @@ -25,4 +34,4 @@ protocol ReferendumVoteSetupInteractorOutputProtocol: ReferendumVoteInteractorOu func didReceiveError(_ error: ReferendumVoteSetupInteractorError) } -protocol ReferendumVoteSetupWireframeProtocol: AnyObject {} +protocol ReferendumVoteSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, FeeRetryable {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift index 3d573690d3..d75e2e8bba 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -1,11 +1,14 @@ import UIKit import SoraFoundation +import CommonWallet -final class ReferendumVoteSetupViewController: UIViewController { +final class ReferendumVoteSetupViewController: UIViewController, ViewHolder { typealias RootViewType = ReferendumVoteSetupViewLayout let presenter: ReferendumVoteSetupPresenterProtocol + private var referendumNumber: String? + init( presenter: ReferendumVoteSetupPresenterProtocol, localizationManager: LocalizationManagerProtocol @@ -28,13 +31,77 @@ final class ReferendumVoteSetupViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + setupLocalization() + presenter.setup() } - private func setupLocalization() {} + private func setupLocalization() { + let languages = selectedLocale.rLanguages + + applyReferendumNumber() + + rootView.amountView.titleView.text = R.string.localizable.walletSendAmountTitle( + preferredLanguages: languages + ) + + rootView.amountView.detailsTitleLabel.text = R.string.localizable.commonAvailablePrefix( + preferredLanguages: languages + ) + + rootView.convictionView.titleLabel.text = R.string.localizable.govVoteConvictionTitle( + preferredLanguages: languages + ) + + rootView.lockAmountTitleLabel.text = R.string.localizable.commonGovLock(preferredLanguages: languages) + rootView.lockPeriodTitleLabel.text = R.string.localizable.commonLockingPeriod(preferredLanguages: languages) + + rootView.feeView.locale = selectedLocale + + let hint = R.string.localizable.govVoteSetupHint(preferredLanguages: languages) + rootView.hintListView.bind(texts: [hint]) + + rootView.nayButton.imageWithTitleView?.title = R.string.localizable.governanceNay(preferredLanguages: languages) + rootView.ayeButton.imageWithTitleView?.title = R.string.localizable.governanceAye(preferredLanguages: languages) + } + + private func applyReferendumNumber() { + let languages = selectedLocale.rLanguages + + rootView.titleLabel.text = R.string.localizable.govVoteSetupTitleFormat( + referendumNumber ?? "", + preferredLanguages: languages + ) + } } -extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol {} +extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol { + func didReceive(referendumNumber: String) { + self.referendumNumber = referendumNumber + + applyReferendumNumber() + } + + func didReceiveBalance(viewModel: String) { + rootView.amountView.detailsValueLabel.text = viewModel + } + + func didReceiveInputChainAsset(viewModel: ChainAssetViewModel) { + rootView.amountInputView.bind(assetViewModel: viewModel.assetViewModel) + } + + func didReceiveAmount(inputViewModel: AmountInputViewModelProtocol) { + rootView.amountInputView.bind(inputViewModel: inputViewModel) + } + + func didReceiveFee(viewModel: BalanceViewModelProtocol?) { + rootView.feeView.bind(viewModel: viewModel) + } + + func didReceiveAmountInputPrice(viewModel: String?) { + rootView.amountInputView.bind(priceViewModel: viewModel) + } +} extension ReferendumVoteSetupViewController: Localizable { func applyLocalization() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index b8a3453e7b..f3ce6440c1 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -9,6 +9,8 @@ struct ReferendumVoteSetupViewFactory { referendum: ReferendumIdLocal ) -> ReferendumVoteSetupViewProtocol? { guard + let chain = state.settings.value, + let assetDisplayInfo = chain.utilityAsset()?.displayInfo(with: chain.icon), let currencyManager = CurrencyManager.shared, let interactor = createInteractor( for: state, @@ -20,7 +22,27 @@ struct ReferendumVoteSetupViewFactory { let wireframe = ReferendumVoteSetupWireframe() - let presenter = ReferendumVoteSetupPresenter(interactor: interactor, wireframe: wireframe) + let localizationManager = LocalizationManager.shared + + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: assetDisplayInfo, + priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) + ) + + let networkViewModelFactory = NetworkViewModelFactory() + let chainAssetViewModelFactory = ChainAssetViewModelFactory(networkViewModelFactory: networkViewModelFactory) + + let presenter = ReferendumVoteSetupPresenter( + chain: chain, + referendumIndex: referendum, + balanceViewModelFactory: balanceViewModelFactory, + referendumFormatter: NumberFormatter.index.localizableResource(), + chainAssetViewModelFactory: chainAssetViewModelFactory, + interactor: interactor, + wireframe: wireframe, + localizationManager: localizationManager, + logger: Logger.shared + ) let view = ReferendumVoteSetupViewController( presenter: presenter, @@ -38,29 +60,30 @@ struct ReferendumVoteSetupViewFactory { referendum: ReferendumIdLocal, currencyManager: CurrencyManagerProtocol ) -> ReferendumVoteSetupInteractor? { + let wallet: MetaAccountModel? = SelectedWalletSettings.shared.value + guard let chain = state.settings.value, - let selectedAccount = SelectedWalletSettings.shared.value?.fetchMetaChainAccount( - for: chain.accountRequest() - ), + let selectedAccount = wallet?.fetchMetaChainAccount(for: chain.accountRequest()), let subscriptionFactory = state.subscriptionFactory, let blockTimeService = state.blockTimeService else { return nil } - let chainRegistry = state.chainRegistry - guard - let connection = chainRegistry.getConnection(for: chain.chainId), - let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + let connection = state.chainRegistry.getConnection(for: chain.chainId), + let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId) else { return nil } let operationQueue = OperationManagerFacade.sharedDefaultQueue let operationManager = OperationManager(operationQueue: operationQueue) - let requestFactory = StorageRequestFactory(remoteFactory: StorageKeyFactory(), operationManager: operationManager) + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: operationManager + ) let lockStateFactory = Gov2LockStateFactory(requestFactory: requestFactory) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index 736d9da470..90059dff52 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -1,6 +1,9 @@ import UIKit final class ReferendumVoteSetupViewLayout: UIView { + typealias MappingView = GenericPairValueView + typealias ChangesView = GenericPairValueView + let containerView: ScrollableContainerView = { let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) view.stackView.layoutMargins = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 0.0, right: 16.0) @@ -25,7 +28,7 @@ final class ReferendumVoteSetupViewLayout: UIView { let titleLabel: UILabel = .create { view in view.textColor = R.color.colorWhite() - view.font = .regularSubheadline + view.font = .title2 view.numberOfLines = 0 } @@ -35,9 +38,25 @@ final class ReferendumVoteSetupViewLayout: UIView { let convictionView = ReferendumConvictionView() - let lockedAmountView = ReferendumVoteSetupViewLayout.createMultiValueView() + var lockAmountTitleLabel: UILabel { + lockedAmountView.titleView.detailsLabel + } + + let lockedAmountView: GenericTitleValueView = { + let view = ReferendumVoteSetupViewLayout.createMultiValueView() + view.titleView.imageView.image = R.image.iconLock()?.tinted(with: R.color.colorWhite48()!) + return view + }() - let lockedPeriodView = ReferendumVoteSetupViewLayout.createMultiValueView() + var lockPeriodTitleLabel: UILabel { + lockedPeriodView.titleView.detailsLabel + } + + let lockedPeriodView: GenericTitleValueView = { + let view = ReferendumVoteSetupViewLayout.createMultiValueView() + view.titleView.imageView.image = R.image.iconPending()?.tinted(with: R.color.colorWhite48()!) + return view + }() let feeView: NetworkFeeView = { let view = UIFactory.default.createNetwork26FeeView() @@ -64,14 +83,14 @@ final class ReferendumVoteSetupViewLayout: UIView { addSubview(nayButton) nayButton.snp.makeConstraints { make in make.leading.equalToSuperview().inset(UIConstants.horizontalInset) - make.trailing.equalTo(safeAreaLayoutGuide.snp.centerX).inset(8.0) + make.trailing.equalTo(safeAreaLayoutGuide.snp.centerX).offset(-8.0) make.bottom.equalTo(safeAreaLayoutGuide).inset(UIConstants.actionBottomInset) make.height.equalTo(UIConstants.actionHeight) } addSubview(ayeButton) ayeButton.snp.makeConstraints { make in - make.leading.equalTo(safeAreaLayoutGuide.snp.centerX).inset(8.0) + make.leading.equalTo(safeAreaLayoutGuide.snp.centerX).offset(8.0) make.trailing.equalToSuperview().inset(UIConstants.horizontalInset) make.bottom.equalTo(safeAreaLayoutGuide).inset(UIConstants.actionBottomInset) make.height.equalTo(UIConstants.actionHeight) @@ -84,6 +103,9 @@ final class ReferendumVoteSetupViewLayout: UIView { } containerView.stackView.addArrangedSubview(titleLabel) + + containerView.stackView.setCustomSpacing(16.0, after: titleLabel) + containerView.stackView.addArrangedSubview(amountView) containerView.stackView.addArrangedSubview(amountInputView) @@ -102,20 +124,48 @@ final class ReferendumVoteSetupViewLayout: UIView { containerView.stackView.setCustomSpacing(16.0, after: convictionView) containerView.stackView.addArrangedSubview(lockedAmountView) + + lockedAmountView.snp.makeConstraints { make in + make.height.equalTo(34.0) + } + containerView.stackView.addArrangedSubview(lockedPeriodView) + + lockedPeriodView.snp.makeConstraints { make in + make.height.equalTo(34.0) + } + containerView.stackView.addArrangedSubview(feeView) + + containerView.stackView.setCustomSpacing(16.0, after: feeView) + containerView.stackView.addArrangedSubview(hintListView) } - static func createMultiValueView( - ) -> GenericTitleValueView> { - let view = GenericTitleValueView>() - view.titleView.textColor = R.color.colorWhite() - view.titleView.font = .regularSubheadline - view.valueView.valueTop.textColor = R.color.colorTransparentText() - view.valueView.valueTop.font = .regularFootnote - view.valueView.valueBottom.detailsLabel.textColor = R.color.colorNovaBlue() - view.valueView.valueBottom.detailsLabel.font = .regularFootnote + static func createMultiValueView() -> GenericTitleValueView { + let view = GenericTitleValueView() + view.titleView.spacing = 8.0 + view.titleView.mode = .iconDetails + view.titleView.iconWidth = 16.0 + view.titleView.detailsLabel.textColor = R.color.colorTransparentText() + view.titleView.detailsLabel.font = .regularFootnote + + view.valueView.setVerticalAndSpacing(0.0) + + let mappingView = view.valueView.fView + mappingView.setHorizontalAndSpacing(4.0) + mappingView.fView.iconWidth = 12.0 + mappingView.fView.spacing = 4.0 + mappingView.fView.detailsLabel.textColor = R.color.colorTransparentText() + mappingView.fView.detailsLabel.font = .regularFootnote + mappingView.sView.textColor = R.color.colorWhite() + mappingView.sView.font = .regularFootnote + + let changesView = view.valueView.sView + changesView.mode = .iconDetails + changesView.spacing = 0.0 + changesView.detailsLabel.textColor = R.color.colorNovaBlue() + changesView.detailsLabel.font = .caption1 return view } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 4472662681..0d4c8916cf 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1026,3 +1026,9 @@ "gov.common.votes.format" = "%@ votes"; "gov.common.amount.conviction.format" = "%@ × %@x"; "gov.voters.empty" = "When somebody votes for\nthe referendum they will appear here"; +"gov.vote.conviction.title" = "Multiply votes by increasing locking period"; +"common.gov.lock" = "Governance lock"; +"common.locking.period" = "Locking period"; +"gov.vote.setup.hint" = "After locking period don’t forget to unlock your tokens"; +"gov.vote.setup.title.format" = "Vote for Referendum %@"; +"common.available.prefix" = "Available:"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 2ba45caed6..4234651efb 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1027,3 +1027,9 @@ "gov.common.votes.format" = "%@ голосов"; "gov.common.amount.conviction.format" = "%@ × %@x"; "gov.voters.empty" = "Когда кто-нибудь проголосует\nза референдум они будут отображаться здесь"; +"gov.vote.conviction.title" = "Умножить голос, увеличивая период блокировки"; +"common.gov.lock" = "Блокировка в голосовании"; +"common.locking.period" = "Период блокировки"; +"gov.vote.setup.hint" = "После окончания периода блокировки не забудьте забрать токены"; +"gov.vote.setup.title.format" = "Голосование за референдум %@"; +"common.available.prefix" = "Доступно:"; From 3d74b6a1db7a221641f91ccc35e6c88e74e92272 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 20 Oct 2022 12:59:12 +0500 Subject: [PATCH 067/229] add handlers --- .../Common/View/DiscreteGradientSlider.swift | 5 ++ .../ReferendumVoteSetupPresenter.swift | 74 ++++++++++++++++-- .../ReferendumVoteSetupProtocols.swift | 7 ++ .../ReferendumVoteSetupViewController.swift | 77 +++++++++++++++++++ .../View/ReferendumConvictionView.swift | 6 ++ 5 files changed, 164 insertions(+), 5 deletions(-) diff --git a/novawallet/Common/View/DiscreteGradientSlider.swift b/novawallet/Common/View/DiscreteGradientSlider.swift index f6315c7acd..ed8ec10b67 100644 --- a/novawallet/Common/View/DiscreteGradientSlider.swift +++ b/novawallet/Common/View/DiscreteGradientSlider.swift @@ -299,7 +299,12 @@ class DiscreteGradientSlider: UIControl { let diff = round((location - stepPositionX(for: 0)) / step) + let oldValue = value value = min(numberOfValues - 1, UInt(max(0, Int(diff)))) + + if oldValue != value { + sendActions(for: .valueChanged) + } } override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 706f27f2d7..5f1c4404e7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -13,6 +13,7 @@ final class ReferendumVoteSetupPresenter { let balanceViewModelFactory: BalanceViewModelFactoryProtocol let referendumFormatter: LocalizableResource let chainAssetViewModelFactory: ChainAssetViewModelFactoryProtocol + let refendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol let logger: LoggerProtocol private var assetBalance: AssetBalance? @@ -24,7 +25,8 @@ final class ReferendumVoteSetupPresenter { private var referendum: ReferendumLocal? private var lockDiff: GovernanceLockStateDiff? - var inputResult: AmountInputResult? + private(set) var inputResult: AmountInputResult? + private(set) var conviction: ConvictionVoting.Conviction = .none init( chain: ChainModel, @@ -32,6 +34,7 @@ final class ReferendumVoteSetupPresenter { balanceViewModelFactory: BalanceViewModelFactoryProtocol, referendumFormatter: LocalizableResource, chainAssetViewModelFactory: ChainAssetViewModelFactoryProtocol, + refendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol, interactor: ReferendumVoteSetupInteractorInputProtocol, wireframe: ReferendumVoteSetupWireframeProtocol, localizationManager: LocalizationManagerProtocol, @@ -42,6 +45,7 @@ final class ReferendumVoteSetupPresenter { self.balanceViewModelFactory = balanceViewModelFactory self.chainAssetViewModelFactory = chainAssetViewModelFactory self.referendumFormatter = referendumFormatter + self.refendumStringsViewModelFactory = refendumStringsViewModelFactory self.interactor = interactor self.wireframe = wireframe self.logger = logger @@ -149,12 +153,33 @@ final class ReferendumVoteSetupPresenter { view?.didReceiveAmount(inputViewModel: viewModel) } + private func updateVotesView() { + guard let vote = deriveNewVote() else { + return + } + + let voteValue = vote.voteAction.conviction.votes(for: vote.voteAction.amount) ?? 0 + + let voteString = refendumStringsViewModelFactory.createVotes( + from: voteValue, + chain: chain, + locale: selectedLocale + ) + + view?.didReceiveVotes(viewModel: voteString ?? "") + } + + private func provideConviction() { + view?.didReceiveConviction(viewModel: UInt(conviction.rawValue)) + } + private func updateView() { provideReferendumIndex() updateAvailableBalanceView() provideAmountInputViewModel() updateChainAssetViewModel() updateAmountPriceView() + updateVotesView() updateFeeView() } @@ -169,7 +194,7 @@ final class ReferendumVoteSetupPresenter { let voteAction = ReferendumVoteAction( amount: amountInPlank, - conviction: .none, + conviction: conviction, isAye: true ) @@ -184,7 +209,7 @@ final class ReferendumVoteSetupPresenter { interactor.estimateFee(for: newVote.voteAction) } - private func refereshLockDiff() { + private func refreshLockDiff() { guard let votesResult = votesResult, let newVote = deriveNewVote() else { return } @@ -199,6 +224,45 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { interactor.setup() } + + func updateAmount(_ newValue: Decimal?) { + inputResult = newValue.map { .absolute($0) } + + refreshFee() + refreshLockDiff() + updateAmountPriceView() + } + + func selectAmountPercentage(_ percentage: Float) { + inputResult = .rate(Decimal(Double(percentage))) + + provideAmountInputViewModel() + + refreshFee() + refreshLockDiff() + updateAmountPriceView() + } + + func selectConvictionValue(_ value: UInt) { + guard let newConviction = ConvictionVoting.Conviction(rawValue: UInt8(value)) else { + return + } + + conviction = newConviction + + updateVotesView() + + refreshFee() + refreshLockDiff() + } + + func proceedNay() { + + } + + func proceedAye() { + + } } extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProtocol { @@ -211,7 +275,7 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto ) { self.votesResult = votesResult - refereshLockDiff() + refreshLockDiff() } func didReceiveBlockNumber(_: BlockNumber) {} @@ -232,7 +296,7 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto } case .stateDiffFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in - self?.refereshLockDiff() + self?.refreshLockDiff() } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index 1f1cbe7933..acf66799b7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -8,10 +8,17 @@ protocol ReferendumVoteSetupViewProtocol: ControllerBackedProtocol { func didReceiveAmount(inputViewModel: AmountInputViewModelProtocol) func didReceiveFee(viewModel: BalanceViewModelProtocol?) func didReceiveAmountInputPrice(viewModel: String?) + func didReceiveVotes(viewModel: String) + func didReceiveConviction(viewModel: UInt) } protocol ReferendumVoteSetupPresenterProtocol: AnyObject { func setup() + func updateAmount(_ newValue: Decimal?) + func selectAmountPercentage(_ percentage: Float) + func selectConvictionValue(_ value: UInt) + func proceedNay() + func proceedAye() } protocol ReferendumVoteSetupInteractorInputProtocol: ReferendumVoteInteractorInputProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift index d75e2e8bba..2a59226bba 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -31,11 +31,38 @@ final class ReferendumVoteSetupViewController: UIViewController, ViewHolder { override func viewDidLoad() { super.viewDidLoad() + setupHandlers() setupLocalization() presenter.setup() } + private func setupHandlers() { + rootView.amountInputView.addTarget( + self, + action: #selector(actionAmountChange), + for: .editingChanged + ) + + rootView.nayButton.addTarget( + self, + action: #selector(actionVoteNay), + for: .touchUpInside + ) + + rootView.ayeButton.addTarget( + self, + action: #selector(actionVoteAye), + for: .touchUpInside + ) + + rootView.convictionView.slider.addTarget( + self, + action: #selector(actionConvictionChanged), + for: .valueChanged + ) + } + private func setupLocalization() { let languages = selectedLocale.rLanguages @@ -63,6 +90,8 @@ final class ReferendumVoteSetupViewController: UIViewController, ViewHolder { rootView.nayButton.imageWithTitleView?.title = R.string.localizable.governanceNay(preferredLanguages: languages) rootView.ayeButton.imageWithTitleView?.title = R.string.localizable.governanceAye(preferredLanguages: languages) + + setupAmountInputAccessoryView(for: selectedLocale) } private func applyReferendumNumber() { @@ -73,6 +102,32 @@ final class ReferendumVoteSetupViewController: UIViewController, ViewHolder { preferredLanguages: languages ) } + + private func setupAmountInputAccessoryView(for locale: Locale) { + let accessoryView = UIFactory.default.createAmountAccessoryView( + for: self, + locale: locale + ) + + rootView.amountInputView.textField.inputAccessoryView = accessoryView + } + + @objc private func actionVoteNay() { + presenter.proceedNay() + } + + @objc private func actionVoteAye() { + presenter.proceedAye() + } + + @objc private func actionConvictionChanged() { + presenter.selectConvictionValue(rootView.convictionView.slider.value) + } + + @objc func actionAmountChange() { + let amount = rootView.amountInputView.inputViewModel?.decimalAmount + presenter.updateAmount(amount) + } } extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol { @@ -101,6 +156,28 @@ extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol { func didReceiveAmountInputPrice(viewModel: String?) { rootView.amountInputView.bind(priceViewModel: viewModel) } + + func didReceiveVotes(viewModel: String) { + rootView.convictionView.bind(votes: viewModel) + } + + func didReceiveConviction(viewModel: UInt) { + if viewModel < rootView.convictionView.slider.numberOfValues { + rootView.convictionView.slider.value = viewModel + } + } +} + +extension ReferendumVoteSetupViewController: AmountInputAccessoryViewDelegate { + func didSelect(on _: AmountInputAccessoryView, percentage: Float) { + rootView.amountInputView.textField.resignFirstResponder() + + presenter.selectAmountPercentage(percentage) + } + + func didSelectDone(on _: AmountInputAccessoryView) { + rootView.amountInputView.textField.resignFirstResponder() + } } extension ReferendumVoteSetupViewController: Localizable { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift index 46d459144c..e253734c41 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift @@ -37,6 +37,12 @@ final class ReferendumConvictionView: UIView { fatalError("init(coder:) has not been implemented") } + func bind(votes: String) { + votesView.text = votes + + setNeedsLayout() + } + private func setupLayout() { addSubview(backgroundView) From 61d768a3e839fd4e22ed011d42360f60afe7f865 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 20 Oct 2022 11:38:14 +0300 Subject: [PATCH 068/229] PR fixes #1 --- novawallet.xcodeproj/project.pbxproj | 4 +++ .../ReferendumDetailsProtocols.swift | 12 +++---- .../ReferendumDetailsViewController.swift | 36 ++++++++----------- .../ReferendumDetailsViewLayout.swift | 26 ++++++-------- .../View/Rows/FullDetailsRow.swift | 18 ++++------ .../View/Rows/ReferendumDAppCellView.swift | 2 ++ .../View/Rows/RequestedAmountRow.swift | 31 +++++----------- .../View/Rows/RoundedView+Styles.swift | 23 ++++++++++++ .../View/Rows/TimelineRow.swift | 5 +-- .../View/Rows/VotingDetailsRow.swift | 6 ++-- .../View/Rows/YourVoteRow.swift | 23 ++++-------- .../Governance/View/ReferendumInfoView.swift | 2 +- .../Vote/Governance/View/UILabel+Style.swift | 26 +++++++++++--- 13 files changed, 107 insertions(+), 107 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RoundedView+Styles.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index d535be7c5a..43a72b2a1d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2197,6 +2197,7 @@ 880855F828D09DA8004255E7 /* CrowdloanContributionDataMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855F728D09DA8004255E7 /* CrowdloanContributionDataMapper.swift */; }; 880855FA28D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855F928D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift */; }; 880855FC28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */; }; + 88107D5F290133F8001AB0B0 /* RoundedView+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */; }; 882808C829009CA500AE8089 /* DotsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C729009CA500AE8089 /* DotsView.swift */; }; 882808CA29009CDC00AE8089 /* UIView+frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C929009CDC00AE8089 /* UIView+frame.swift */; }; 8828C05828B4A67000555CB6 /* Prism.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8828C05728B4A67000555CB6 /* Prism.swift */; }; @@ -5085,6 +5086,7 @@ 880855F728D09DA8004255E7 /* CrowdloanContributionDataMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionDataMapper.swift; sourceTree = ""; }; 880855F928D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionLocalSubscriptionFactory.swift; sourceTree = ""; }; 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloansLocalStorageSubscriber.swift; sourceTree = ""; }; + 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RoundedView+Styles.swift"; sourceTree = ""; }; 8821119C96944A0E3526E93A /* StakingRedeemViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRedeemViewFactory.swift; sourceTree = ""; }; 882808C729009CA500AE8089 /* DotsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotsView.swift; sourceTree = ""; }; 882808C929009CDC00AE8089 /* UIView+frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+frame.swift"; sourceTree = ""; }; @@ -12202,6 +12204,7 @@ 88F34FDA28FFE6AA00712BDE /* RequestedAmountRow.swift */, 88F34FDE28FFEAE500712BDE /* TimelineRow.swift */, 88F34FE028FFEAFD00712BDE /* VotingDetailsRow.swift */, + 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */, ); path = Rows; sourceTree = ""; @@ -15246,6 +15249,7 @@ 846A683027469BD500D1A47A /* CrowdloanOffchainProviderFactory.swift in Sources */, 84C11F1C2842B869007F7C05 /* ParaStkCollatorFiltersViewModel.swift in Sources */, AEE5FB1626457AA9002B8FDC /* StakingRewardDestSetupPresenter.swift in Sources */, + 88107D5F290133F8001AB0B0 /* RoundedView+Styles.swift in Sources */, 8468B86E24F63D1400B76BC6 /* AddAccount+OnboardingMainWireframe.swift in Sources */, 84729741260A9C13009B86D0 /* DisplayAddress.swift in Sources */, 8499FEE027C0AE3200712589 /* KnownChainIds.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index dfa2e1bcf7..987c43feba 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -1,10 +1,10 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { - func set(votingDetails: ReferendumVotingStatusDetailsView.Model) - func set(dAppModels: [ReferendumDAppView.Model]) - func set(timelineModel: ReferendumTimelineView.Model) - func set(titleModel: ReferendumDetailsTitleView.Model) - func set(yourVoteModel: YourVoteRow.Model?) - func set(requestedAmount: RequestedAmountRow.Model?) + func didReceive(votingDetails: ReferendumVotingStatusDetailsView.Model) + func didReceive(dAppModels: [ReferendumDAppView.Model]) + func didReceive(timelineModel: ReferendumTimelineView.Model) + func didReceive(titleModel: ReferendumDetailsTitleView.Model) + func didReceive(yourVoteModel: YourVoteRow.Model?) + func didReceive(requestedAmount: RequestedAmountRow.Model?) } protocol ReferendumDetailsPresenterProtocol: AnyObject { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 71fc97fd29..a756a0066c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -43,7 +43,7 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { nayMessage: "Nay: 0.1%" ) ) - set(votingDetails: .init( + didReceive(votingDetails: .init( status: status, votingProgress: votingProgress, aye: .init( @@ -60,7 +60,7 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { )) let iconUrl = URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/chains/white/Polkadot.svg")! - set(dAppModels: [ + didReceive(dAppModels: [ .init( icon: RemoteImageViewModel(url: iconUrl), title: "Polkassembly", @@ -83,7 +83,7 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { let optIcon = metaAccount.walletIdenticonData().flatMap { try? PolkadotIconGenerator().generateFromAccountId($0) } let iconViewModel = optIcon.map { DrawableIconViewModel(icon: $0) } - set(titleModel: .init( + didReceive(titleModel: .init( track: .init( titleIcon: .init(title: "main agenda", icon: nil), referendumNumber: "224" @@ -97,7 +97,7 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { ) ) - set(timelineModel: .init(title: "Timeline", statuses: [ + didReceive(timelineModel: .init(title: "Timeline", statuses: [ .init(title: "One", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), .init(title: "Two", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), .init(title: "Three", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) @@ -105,12 +105,12 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { rootView.fullDetailsView.bind(title: "Full details") - set(yourVoteModel: .init( + didReceive(yourVoteModel: .init( vote: .init(title: "AYE", description: "Your vote"), amount: .init(topValue: "30 votes", bottomValue: "10 KSM × 3x") )) - set(requestedAmount: .init( + didReceive(requestedAmount: .init( title: "Requested amount", amount: .init(topValue: "1,000 KSM", bottomValue: "$38,230") )) @@ -118,35 +118,27 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { } extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { - func set(votingDetails: ReferendumVotingStatusDetailsView.Model) { + func didReceive(votingDetails: ReferendumVotingStatusDetailsView.Model) { rootView.votingDetailsRow.bind(viewModel: votingDetails) } - func set(dAppModels: [ReferendumDAppView.Model]) { + func didReceive(dAppModels: [ReferendumDAppView.Model]) { rootView.setDApps(models: dAppModels) } - func set(timelineModel: ReferendumTimelineView.Model) { + func didReceive(timelineModel: ReferendumTimelineView.Model) { rootView.timelineRow.bind(viewModel: timelineModel) } - func set(titleModel: ReferendumDetailsTitleView.Model) { + func didReceive(titleModel: ReferendumDetailsTitleView.Model) { rootView.titleView.bind(viewModel: titleModel) } - func set(yourVoteModel: YourVoteRow.Model?) { - if let yourVoteModel = yourVoteModel { - rootView.setYourVote(model: yourVoteModel) - } else { - rootView.removeYourVote() - } + func didReceive(yourVoteModel: YourVoteRow.Model?) { + rootView.setYourVote(model: yourVoteModel) } - func set(requestedAmount: RequestedAmountRow.Model?) { - if let requestedAmount = requestedAmount { - rootView.setRequestedAmount(model: requestedAmount) - } else { - rootView.removeRequestedAmount() - } + func didReceive(requestedAmount: RequestedAmountRow.Model?) { + rootView.setRequestedAmount(model: requestedAmount) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 5d16250210..3308738974 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -56,35 +56,29 @@ final class ReferendumDetailsViewLayout: UIView { } } - func setYourVote(model: YourVoteRow.Model) { + func setYourVote(model: YourVoteRow.Model?) { + guard let yourVoteViewModel = model else { + yourVoteRow.map(containerView.stackView.removeArrangedSubview) + return + } if yourVoteRow == nil { let yourVoteView = YourVoteRow(frame: .zero) containerView.stackView.addArrangedSubview(yourVoteView) yourVoteRow = yourVoteView } - yourVoteRow?.bind(viewModel: model) + yourVoteRow?.bind(viewModel: yourVoteViewModel) } - func removeYourVote() { - guard let yourVoteRow = yourVoteRow else { + func setRequestedAmount(model: RequestedAmountRow.Model?) { + guard let requestedAmountViewModel = model else { + requestedAmountRow.map(containerView.stackView.removeArrangedSubview) return } - containerView.stackView.removeArrangedSubview(yourVoteRow) - } - - func setRequestedAmount(model: RequestedAmountRow.Model) { if requestedAmountRow == nil { let requestedAmountView = RequestedAmountRow(frame: .zero) containerView.stackView.addArrangedSubview(requestedAmountView) requestedAmountRow = requestedAmountView } - requestedAmountRow?.bind(viewModel: model) - } - - func removeRequestedAmount() { - guard let requestedAmountRow = requestedAmountRow else { - return - } - containerView.stackView.removeArrangedSubview(requestedAmountRow) + requestedAmountRow?.bind(viewModel: requestedAmountViewModel) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift index 6de2a713ca..0c2d0d1f5d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift @@ -1,24 +1,20 @@ import UIKit +import SoraUI final class FullDetailsRow: RowView> { - let titleLabel = UILabel(style: .rowLink, textAlignment: .left) - let arrowView = UIImageView(image: R.image.iconChevronRight()) - lazy var contentMultiValueView = GenericTitleValueView( - titleView: titleLabel, - valueView: arrowView - ) - override init(frame: CGRect) { super.init(frame: frame) - contentView = contentMultiValueView - backgroundView = TriangularedBlurView() - contentInsets = .init(top: 14, left: 16, bottom: 14, right: 16) + rowContentView.titleView.apply(style: .rowLink) + rowContentView.titleView.textAlignment = .left + rowContentView.valueView.image = R.image.iconChevronRight() + roundedBackgroundView.apply(style: .roundedSelectableCell) preferredHeight = 52 + contentInsets = .init(top: 14, left: 16, bottom: 14, right: 16) backgroundColor = .clear } func bind(title: String) { - titleLabel.text = title + rowContentView.titleView.text = title } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift index 206e977dd9..24c606a583 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift @@ -3,6 +3,8 @@ import UIKit final class ReferendumDAppCellView: RowView, StackTableViewCellProtocol { override init(frame: CGRect) { super.init(frame: frame) + + roundedBackgroundView.apply(style: .roundedSelectableCell) backgroundColor = .clear preferredHeight = 64 } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift index 546764652e..01f29e04c4 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift @@ -6,36 +6,23 @@ final class RequestedAmountRow: RowView> { let amount: MultiValueView.Model } - var titleLabel: UILabel { rowContentView.valueTop } - - let amountView: MultiValueView = .create { - $0.apply(style: .accentAmount) - $0.valueTop.textAlignment = .left - $0.valueBottom.textAlignment = .left - } - - lazy var contentMultiValueView = GenericMultiValueView(valueBottom: amountView) - override init(frame: CGRect) { super.init(frame: frame) - setup() - } - - private func setup() { - contentView = contentMultiValueView preferredHeight = 102 - rowContentView.spacing = 2 - rowContentView.valueBottom.spacing = 2 - titleLabel.apply(style: .footnoteWhite64) - titleLabel.textAlignment = .left - backgroundView = TriangularedBlurView() + rowContentView.valueTop.apply(style: .footnoteWhite64) + rowContentView.valueTop.textAlignment = .left + rowContentView.valueBottom.apply(style: .accentAmount) + rowContentView.valueBottom.valueTop.textAlignment = .left + rowContentView.valueBottom.valueBottom.textAlignment = .left + roundedBackgroundView.apply(style: .roundedView) contentInsets = .init(top: 16, left: 16, bottom: 16, right: 16) backgroundColor = .clear + isUserInteractionEnabled = false } func bind(viewModel: Model) { - titleLabel.text = viewModel.title - amountView.bind(viewModel: viewModel.amount) + rowContentView.valueTop.text = viewModel.title + rowContentView.valueBottom.bind(viewModel: viewModel.amount) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RoundedView+Styles.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RoundedView+Styles.swift new file mode 100644 index 0000000000..ea5b2399c5 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RoundedView+Styles.swift @@ -0,0 +1,23 @@ +import UIKit +import SoraUI + +extension RoundedView.Style { + static let roundedSelectableCell = RoundedView.Style( + shadowOpacity: 0, + strokeWidth: 0, + strokeColor: .clear, + highlightedStrokeColor: .clear, + fillColor: R.color.colorWhite8()!, + highlightedFillColor: R.color.colorAccentSelected()!, + rounding: .init(radius: 12, corners: .allCorners) + ) + static let roundedView = RoundedView.Style( + shadowOpacity: 0, + strokeWidth: 0, + strokeColor: .clear, + highlightedStrokeColor: .clear, + fillColor: R.color.colorWhite8()!, + highlightedFillColor: .clear, + rounding: .init(radius: 12, corners: .allCorners) + ) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift index 7d1a28da2c..c2aad26d02 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift @@ -1,13 +1,10 @@ import UIKit final class TimelineRow: RowView { - let referendumTimelineView = ReferendumTimelineView() - override init(frame: CGRect) { super.init(frame: frame) - contentView = referendumTimelineView - backgroundView = TriangularedBlurView() + roundedBackgroundView.apply(style: .roundedView) contentInsets = .init(top: 16, left: 16, bottom: 0, right: 16) backgroundColor = .clear } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift index 9cde279050..7adaadd618 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift @@ -1,14 +1,12 @@ import UIKit final class VotingDetailsRow: RowView { - let referendumVotingStatusDetailsView = ReferendumVotingStatusDetailsView() - override init(frame: CGRect) { super.init(frame: frame) - contentView = referendumVotingStatusDetailsView + isUserInteractionEnabled = true contentInsets = .zero - backgroundView = TriangularedBlurView() + roundedBackgroundView.apply(style: .roundedView) backgroundColor = .clear } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift index 7befd6c955..c8102d32dc 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift @@ -6,30 +6,19 @@ final class YourVoteRow: RowView( - titleView: voteView, - valueView: amountView - ) - override init(frame: CGRect) { super.init(frame: frame) - contentView = contentMultiValueView - backgroundView = TriangularedBlurView() + rowContentView.titleView.apply(style: .ayeInverse) + rowContentView.valueView.apply(style: .rowContrasted) + roundedBackgroundView.apply(style: .roundedView) contentInsets = .init(top: 9, left: 16, bottom: 9, right: 16) + isUserInteractionEnabled = false preferredHeight = 52 backgroundColor = .clear } func bind(viewModel: Model) { - voteView.bind(viewModel: viewModel.vote) - amountView.bind(viewModel: viewModel.amount) + rowContentView.titleView.bind(viewModel: viewModel.vote) + rowContentView.valueView.bind(viewModel: viewModel.amount) } } diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift index 0d16302f1f..acec0e1a63 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -195,6 +195,6 @@ extension RoundedView.Style { static let referendum = RoundedView.Style( fillColor: R.color.colorWhite8()!, highlightedFillColor: R.color.colorAccentSelected()!, - cornerRadius: 8 + rounding: .init(radius: 8, corners: .allCorners) ) } diff --git a/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift index 05f3374f37..676f7ba05d 100644 --- a/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift +++ b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift @@ -22,15 +22,33 @@ extension UILabel { extension RoundedView { struct Style { - let fillColor: UIColor - let highlightedFillColor: UIColor - let cornerRadius: CGFloat + var shadowOpacity: CFloat? + var strokeWidth: CGFloat? + var strokeColor: UIColor? + var highlightedStrokeColor: UIColor? + var fillColor: UIColor + var highlightedFillColor: UIColor + var rounding: Rounding? + + struct Rounding { + let radius: CGFloat + let corners: UIRectCorner + } } func apply(style: Style) { + style.shadowOpacity.map { shadowOpacity = $0 } + style.strokeWidth.map { strokeWidth = $0 } + style.strokeColor.map { strokeColor = $0 } + style.highlightedStrokeColor.map { highlightedStrokeColor = $0 } + fillColor = style.fillColor highlightedFillColor = style.highlightedFillColor - cornerRadius = style.cornerRadius + + style.rounding.map { + roundingCorners = $0.corners + cornerRadius = $0.radius + } } } From c949a293666973af343e75c85bc5f5d23a38a2dd Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 20 Oct 2022 13:53:43 +0300 Subject: [PATCH 069/229] PR fixes #2 --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../ReferendumDetailsProtocols.swift | 1 + .../ReferendumDetailsViewController.swift | 17 +++++-- .../View/ReferendumDAppView.swift | 3 +- .../View/ReferendumDetailsTitleView.swift | 45 +++++++------------ .../View/Rows/FullDetailsRow.swift | 1 - .../View/Rows/TimelineRow.swift | 1 + .../View/Rows/VotingDetailsRow.swift | 1 - .../View/TrackTagsView.swift | 42 +++++++++++++++++ 9 files changed, 77 insertions(+), 38 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 43a72b2a1d..7b9ea677b1 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2198,6 +2198,7 @@ 880855FA28D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855F928D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift */; }; 880855FC28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */; }; 88107D5F290133F8001AB0B0 /* RoundedView+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */; }; + 88107D6129015FAB001AB0B0 /* TrackTagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */; }; 882808C829009CA500AE8089 /* DotsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C729009CA500AE8089 /* DotsView.swift */; }; 882808CA29009CDC00AE8089 /* UIView+frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C929009CDC00AE8089 /* UIView+frame.swift */; }; 8828C05828B4A67000555CB6 /* Prism.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8828C05728B4A67000555CB6 /* Prism.swift */; }; @@ -5087,6 +5088,7 @@ 880855F928D0BAA2004255E7 /* CrowdloanContributionLocalSubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionLocalSubscriptionFactory.swift; sourceTree = ""; }; 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloansLocalStorageSubscriber.swift; sourceTree = ""; }; 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RoundedView+Styles.swift"; sourceTree = ""; }; + 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackTagsView.swift; sourceTree = ""; }; 8821119C96944A0E3526E93A /* StakingRedeemViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRedeemViewFactory.swift; sourceTree = ""; }; 882808C729009CA500AE8089 /* DotsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotsView.swift; sourceTree = ""; }; 882808C929009CDC00AE8089 /* UIView+frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+frame.swift"; sourceTree = ""; }; @@ -12128,6 +12130,7 @@ 88A95FA728FAA99D00BE26F3 /* ReferendumDAppView.swift */, 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */, 88F34FD128FF045400712BDE /* BindableView.swift */, + 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */, ); path = View; sourceTree = ""; @@ -15906,6 +15909,7 @@ 8496ADE0276B152500306B24 /* NSDictionary+Map.swift in Sources */, 84300B2826C107AD00D64514 /* ConnectionAutobalancing.swift in Sources */, BD571417BD18C711B76E1D62 /* ExportSeedWireframe.swift in Sources */, + 88107D6129015FAB001AB0B0 /* TrackTagsView.swift in Sources */, 841816732824FD0A0007684A /* StorageListSyncService.swift in Sources */, 8463A73825E3AA47003B8160 /* AccountInfo.swift in Sources */, ABA3D873BBECB7F4BD670872 /* ExportSeedPresenter.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 987c43feba..a1a938cc27 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -5,6 +5,7 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { func didReceive(titleModel: ReferendumDetailsTitleView.Model) func didReceive(yourVoteModel: YourVoteRow.Model?) func didReceive(requestedAmount: RequestedAmountRow.Model?) + func didReceive(trackTagsModel: TrackTagsView.Model?) } protocol ReferendumDetailsPresenterProtocol: AnyObject { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index a756a0066c..e3cab24e6a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -83,11 +83,11 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { let optIcon = metaAccount.walletIdenticonData().flatMap { try? PolkadotIconGenerator().generateFromAccountId($0) } let iconViewModel = optIcon.map { DrawableIconViewModel(icon: $0) } + didReceive(trackTagsModel: .init( + titleIcon: .init(title: "main agenda", icon: nil), + referendumNumber: "224" + )) didReceive(titleModel: .init( - track: .init( - titleIcon: .init(title: "main agenda", icon: nil), - referendumNumber: "224" - ), accountIcon: iconViewModel, accountName: "RTTI-5220", title: "Polkadot and Kusama participation in the 10th Pais Digital Chile Summit.", @@ -141,4 +141,13 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { func didReceive(requestedAmount: RequestedAmountRow.Model?) { rootView.setRequestedAmount(model: requestedAmount) } + + func didReceive(trackTagsModel: TrackTagsView.Model?) { + let barButtonItem: UIBarButtonItem? = trackTagsModel.map { + let trackTagsView = TrackTagsView() + trackTagsView.bind(viewModel: $0) + return .init(customView: trackTagsView) + } + navigationItem.setRightBarButton(barButtonItem, animated: true) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift index 9b2788a0c5..d53028ebe0 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift @@ -48,7 +48,7 @@ final class ReferendumDAppView: UIView { addSubview(content) content.snp.makeConstraints { - $0.edges.equalTo(Constants.contentInsets) + $0.edges.equalToSuperview() } } } @@ -91,6 +91,5 @@ extension ReferendumDAppView { static let horizontalSpace: CGFloat = 12 static let iconWidth: CGFloat = 48 static let iconInsets = UIEdgeInsets(top: 6, left: 6, bottom: 6, right: 6) - static let contentInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index 3747c6c54b..626a5eac49 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -1,21 +1,24 @@ import UIKit -final class ReferendumDetailsTitleView: UIView { - let trackNameView: BorderedIconLabelView = .create { - $0.iconDetailsView.spacing = 6 - $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) - $0.iconDetailsView.detailsLabel.apply(style: .track) - $0.backgroundView.apply(style: .referendum) - $0.iconDetailsView.detailsLabel.numberOfLines = 1 +extension TrackTagsView: BindableView { + struct Model { + let titleIcon: TitleIconViewModel + let referendumNumber: String? } - let numberLabel: BorderedLabelView = .create { - $0.titleLabel.apply(style: .track) - $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) - $0.backgroundView.apply(style: .referendum) - $0.titleLabel.numberOfLines = 1 + func bind(viewModel: Model) { + if let referendumNumber = viewModel.referendumNumber { + numberLabel.isHidden = false + numberLabel.titleLabel.text = referendumNumber + } else { + numberLabel.isHidden = true + } + + trackNameView.iconDetailsView.bind(viewModel: viewModel.titleIcon) } +} +final class ReferendumDetailsTitleView: UIView { let addressView = PolkadotIconDetailsView() let infoImageView = UIImageView() let textView: UITextView = .create { @@ -47,14 +50,6 @@ final class ReferendumDetailsTitleView: UIView { let content = UIView.vStack( spacing: 9, [ - UIView.hStack( - spacing: 6, - [ - UIView(), - trackNameView, - numberLabel - ] - ), UIView.hStack( spacing: 6, [ @@ -82,24 +77,14 @@ final class ReferendumDetailsTitleView: UIView { extension ReferendumDetailsTitleView { struct Model { - let track: Track? let accountIcon: DrawableIconViewModel? let accountName: String let title: String let description: String let buttonText: String - - struct Track { - let titleIcon: TitleIconViewModel - let referendumNumber: String? - } } func bind(viewModel: Model) { - numberLabel.isHidden = viewModel.track?.referendumNumber == nil - trackNameView.iconDetailsView.bind(viewModel: viewModel.track?.titleIcon) - numberLabel.titleLabel.text = viewModel.track?.referendumNumber - viewModel.accountIcon.map { addressView.imageView.fillColor = $0.fillColor addressView.imageView.bind(icon: $0.icon) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift index 0c2d0d1f5d..f5ed70c1ee 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift @@ -11,7 +11,6 @@ final class FullDetailsRow: RowView> roundedBackgroundView.apply(style: .roundedSelectableCell) preferredHeight = 52 contentInsets = .init(top: 14, left: 16, bottom: 14, right: 16) - backgroundColor = .clear } func bind(title: String) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift index c2aad26d02..13e24af0db 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift @@ -4,6 +4,7 @@ final class TimelineRow: RowView { override init(frame: CGRect) { super.init(frame: frame) + isUserInteractionEnabled = false roundedBackgroundView.apply(style: .roundedView) contentInsets = .init(top: 16, left: 16, bottom: 0, right: 16) backgroundColor = .clear diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift index 7adaadd618..8f00e2c04a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift @@ -4,7 +4,6 @@ final class VotingDetailsRow: RowView { override init(frame: CGRect) { super.init(frame: frame) - isUserInteractionEnabled = true contentInsets = .zero roundedBackgroundView.apply(style: .roundedView) backgroundColor = .clear diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift new file mode 100644 index 0000000000..d6caa5a75b --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift @@ -0,0 +1,42 @@ +import UIKit + +final class TrackTagsView: UIView { + let trackNameView: BorderedIconLabelView = .create { + $0.iconDetailsView.spacing = 6 + $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) + $0.iconDetailsView.detailsLabel.apply(style: .track) + $0.backgroundView.apply(style: .referendum) + $0.iconDetailsView.detailsLabel.numberOfLines = 1 + } + + let numberLabel: BorderedLabelView = .create { + $0.titleLabel.apply(style: .track) + $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) + $0.backgroundView.apply(style: .referendum) + $0.titleLabel.numberOfLines = 1 + } + + override init(frame: CGRect) { + super.init(frame: frame) + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + let content = UIView.hStack( + spacing: 6, + [ + trackNameView, + numberLabel + ] + ) + addSubview(content) + content.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } +} From 78e6dbf2ad58a0874fad2e1f1e059ac1b1895fbb Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 20 Oct 2022 18:46:05 +0500 Subject: [PATCH 070/229] add locks display --- novawallet.xcodeproj/project.pbxproj | 16 +++ .../iconAmountDec.imageset/Contents.json | 12 ++ .../iconAmountDec.imageset/iconAmountDec.pdf | Bin 0 -> 2117 bytes .../iconAmountInc.imageset/Contents.json | 12 ++ .../iconAmountInc.imageset/iconAmountInc.pdf | Bin 0 -> 1534 bytes .../iconGovAmountLock.imageset/Contents.json | 12 ++ .../iconGovAmountLock.pdf | Bin 0 -> 1522 bytes .../Contents.json | 12 ++ .../iconGovLockTransition.pdf | Bin 0 -> 1347 bytes .../iconGovPeriodLock.imageset/Contents.json | 12 ++ .../iconGovPeriodLock.pdf | Bin 0 -> 1758 bytes .../Foundation/TimeInterval+Time.swift | 1 + .../ReferendumVoteSetupPresenter.swift | 72 ++++++++-- .../ReferendumVoteSetupProtocols.swift | 2 + .../ReferendumVoteSetupViewController.swift | 8 ++ .../ReferendumVoteSetupViewFactory.swift | 5 + .../ReferendumVoteSetupViewLayout.swift | 39 +++++- .../ReferendumLockChangeViewModel.swift | 12 ++ ...ReferendumLockChangeViewModelFactory.swift | 127 ++++++++++++++++++ .../ReferendumDisplayStringFactory.swift | 2 +- novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 22 files changed, 331 insertions(+), 15 deletions(-) create mode 100644 novawallet/Assets.xcassets/iconAmountDec.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconAmountDec.imageset/iconAmountDec.pdf create mode 100644 novawallet/Assets.xcassets/iconAmountInc.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconAmountInc.imageset/iconAmountInc.pdf create mode 100644 novawallet/Assets.xcassets/iconGovAmountLock.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconGovAmountLock.imageset/iconGovAmountLock.pdf create mode 100644 novawallet/Assets.xcassets/iconGovLockTransition.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconGovLockTransition.imageset/iconGovLockTransition.pdf create mode 100644 novawallet/Assets.xcassets/iconGovPeriodLock.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconGovPeriodLock.imageset/iconGovPeriodLock.pdf create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModel.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 92e9265409..35b0a5e56c 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1264,6 +1264,8 @@ 8487584727F1816300495306 /* QRExtractionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8487584627F1816200495306 /* QRExtractionService.swift */; }; 8487584927F1830D00495306 /* QRImageUploadDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8487584827F1830D00495306 /* QRImageUploadDelegate.swift */; }; 8487584B27F1834E00495306 /* ImageGalleryPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8487584A27F1834E00495306 /* ImageGalleryPresentable.swift */; }; + 84880C4029016F1500CADB06 /* ReferendumLockChangeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84880C3F29016F1500CADB06 /* ReferendumLockChangeViewModel.swift */; }; + 84880C42290172C300CADB06 /* ReferendumLockChangeViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84880C41290172C300CADB06 /* ReferendumLockChangeViewModelFactory.swift */; }; 848841C128D1229000D750E9 /* ParaStkYieldBoostStopError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848841C028D1229000D750E9 /* ParaStkYieldBoostStopError.swift */; }; 84884B5F27A1336500FAC549 /* OrmlAssetExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84884B5E27A1336500FAC549 /* OrmlAssetExtras.swift */; }; 8488ECD7258CDCBC004591CC /* PurchaseCompletionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8488ECD6258CDCBC004591CC /* PurchaseCompletionHandler.swift */; }; @@ -4138,6 +4140,8 @@ 8487584627F1816200495306 /* QRExtractionService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRExtractionService.swift; sourceTree = ""; }; 8487584827F1830D00495306 /* QRImageUploadDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRImageUploadDelegate.swift; sourceTree = ""; }; 8487584A27F1834E00495306 /* ImageGalleryPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGalleryPresentable.swift; sourceTree = ""; }; + 84880C3F29016F1500CADB06 /* ReferendumLockChangeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLockChangeViewModel.swift; sourceTree = ""; }; + 84880C41290172C300CADB06 /* ReferendumLockChangeViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLockChangeViewModelFactory.swift; sourceTree = ""; }; 848841C028D1229000D750E9 /* ParaStkYieldBoostStopError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStopError.swift; sourceTree = ""; }; 84884B5E27A1336500FAC549 /* OrmlAssetExtras.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrmlAssetExtras.swift; sourceTree = ""; }; 8488ECD6258CDCBC004591CC /* PurchaseCompletionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseCompletionHandler.swift; sourceTree = ""; }; @@ -8677,6 +8681,15 @@ path = Service; sourceTree = ""; }; + 84880C3E29016EFE00CADB06 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 84880C3F29016F1500CADB06 /* ReferendumLockChangeViewModel.swift */, + 84880C41290172C300CADB06 /* ReferendumLockChangeViewModelFactory.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; 84893BFA24D9B0D1008F6A3F /* Extensions */ = { isa = PBXGroup; children = ( @@ -12960,6 +12973,7 @@ CEE6BB9D4D5A0E46E857EED4 /* ReferendumVoteSetup */ = { isa = PBXGroup; children = ( + 84880C3E29016EFE00CADB06 /* ViewModel */, 84F76ED4290069E900D7206C /* View */, 8425D0DE28FE736F003B782A /* Model */, 5159EA2661A6CBE123CCF891 /* ReferendumVoteSetupProtocols.swift */, @@ -15484,6 +15498,7 @@ 84C4C2D7255D2B780045B582 /* PinChangeWireframe.swift in Sources */, 845353BB2886E3B4006C871A /* OnboardingMainViewLayout.swift in Sources */, 84FB29992639AC2300BE0FCD /* YourValidatorList+SelectionConfirm.swift in Sources */, + 84880C42290172C300CADB06 /* ReferendumLockChangeViewModelFactory.swift in Sources */, 84D17ED828053E3200F7BAFF /* DAppFavoriteMapper.swift in Sources */, 8493D0DF26FE7D7400A28008 /* ChainRepositoryFactory.swift in Sources */, 8411707C285B1214006F4DFB /* XcmTransfers.swift in Sources */, @@ -16340,6 +16355,7 @@ 8402CC9E275B946100E5BF30 /* DAppItemView.swift in Sources */, FFE19A19E5B4ED67A2C61951 /* DAppSearchProtocols.swift in Sources */, F88D85C73094F6A1FC494D87 /* DAppSearchWireframe.swift in Sources */, + 84880C4029016F1500CADB06 /* ReferendumLockChangeViewModel.swift in Sources */, 84350AD4284580F50031EF24 /* StakingTotalStakePresentable.swift in Sources */, 6B393DCF67CF97FDA580C69B /* DAppSearchPresenter.swift in Sources */, DC682E96D056C069902B9C31 /* DAppSearchViewController.swift in Sources */, diff --git a/novawallet/Assets.xcassets/iconAmountDec.imageset/Contents.json b/novawallet/Assets.xcassets/iconAmountDec.imageset/Contents.json new file mode 100644 index 0000000000..8ac2cbae37 --- /dev/null +++ b/novawallet/Assets.xcassets/iconAmountDec.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "iconAmountDec.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/iconAmountDec.imageset/iconAmountDec.pdf b/novawallet/Assets.xcassets/iconAmountDec.imageset/iconAmountDec.pdf new file mode 100644 index 0000000000000000000000000000000000000000..932ad2652a82b09b4d7b235e3331edabb1ca91cc GIT binary patch literal 2117 zcmZuy+iu%N5PjdTm=~i`(Jc3VDGUR)WEDXg#F2|Uj(MgKGe$b=KvKs&^Cm~M*IxQlToqnrtTYZZ#l6Bg*pWa} zYwJ8HikXBJkV9H1hm=yJqLLZwkU3_Pp5b#0WX@R|c3CZ?lsV$9R%7xMm%3o7Fx+s4 zEG%V0X!xXk9zK1+na8X6>-$p;#a;PWN8oL} z*_Jo$GkiiK=OfI`1f5n>rgh!7hpwu72&c+ArdzblP&fF-aHLG&UD+W9IzrjO6QFb; z6>qj1qza*eHB9eWvemdf}?&~?s zwww8}DaE>N2M7g^4KD7tKWbz@p44SGjOB321-ZDmeYcwYkh=lCbv|XUa^%jP*1REuiC3-qC|mqKQmYCkw`p!sw3>eAl&` zLsfS$+n3e5d-zay{kCm@3##Dr?B=lDZ9wpq^`GbP{(znM0r=$`i9HX$!S&M;OHD5T3dgEU>U3!@Oz(Jf&U42JLe6}$v!2UOPg2T&APlXV!jVO_dgv4iKRZHC0&Yqn)sthUo3 zkROp0$v4#Ea&>XSsU?I1gYL&q0&sc?XJ;g|oA^mY$*WJHy&dmBB3wtSVeCV_C)Fza z**0PQ{v4K92Sj(g@!Nwn8q`q{6ER~ajf15MFZI0rit)708J4~k+W zVFi>(3*|7S?5U_^#yZR#qe;*3937c+)GY1=VHU{}RWU+hDY5@a z6Wnm_jm8SHCW;#2y<@W`1xcD@ze1B7ztn_Lr$`oh3dfT?$IKcIHoOxW;x4*vvRG0N_NZ@nWZ0qyx0j@ET zmm|#0gy!88X&r{{zHh<+@l{!;aLcY8LyI@YCuM?{b&m{mLdC-qQGSrBkJ}BV3bBGU zO!q9id-Ub6@*j{Ck<7D5vA`i;I2XRG$9mV@K6icS!wq3z$y5397mU_Y1LCxBG7mdw zGm@BRTr=|SCE|=>V$ZBNxBev(8nsMTV_$D~p(jzj4=ZfP(a`O~F&u3-$4^bE)?GJ3 eEcnpi>T3HKF#E$xUH9Xm94@&ai^aPy7ykg!p4ywCmlqU z>OApz&zFxEo7LSFr{xAV8MB|k~B=CE%Gr``klVB_K{uHrXA znN77~z^TDM++Cg~%eXBr+Oi^o3NE#=V5m|?Sp}zwaYmKZDdUh*lWA!*a5V7J3>392 z<7hCUl4xqBv`oyP^%@y!OllDYrxHpMnWlm%V^QO5=p%U|eG{>AK0m{Z;THQZ zX=YL;vKdTiX1Qb;Sgf?>So}y(&!$%U`bIYR)f($zC>NYr86rMs(RQ{kc(7=|g_Rl) zSd8sI;g*=i;~P?u&&1DN7^-ms{jd!aY@~>DDI@iB{kE#=u7!uMIOq5zUw;2^kZg** z3*e*M9g5rf1s>+T46WhW*raJSD&?-NpPSOP;BS&V$Sv!ta}|2@*TV=mMS~1fKzKcj zDR?wpLhlbd3>AC^IgEam^)uS?f8uYE%#^Y-C7)m$9Zrcai>^4<`*YKm#yt`oLo#GN z97?591&G7LaSr+qRYZ6yULmV7>+@X}563y;Jkzg{kXXZD*fquB=o;d?_ilydxM=H> pyM&9w?s6zflGk+yKHT|RR{q8C6H@S z$*7e}-Hb{UG}n!#&7eEDiUgIE%6hTA^D|`V&n(Vj3QS_rUM&;vVM#0&LO+eS9A#t0 zfJiEY^xX(?l1eFkuk-)(za&rO@eQfSXW}pNa7)K4?Qd^C5?Y&Z(PcpWpuDZBx@+O# zD-I5>=*#aP4x(LlbOZ3w9g6I>eu0OnU!h4{jP06sW2V%#^>dTE7W`V6yp0k(G)?vU;(%1aD@b9iv#y^pmjA=QMP!yqFEV+7Z74ViUuRub z*2iV&OXD6114H_&>AyiMe}fSo7RPb-3#tGaFTa-S*uZI=^0jYX|YK*jzH*4uWNlfEeny zc~N)uHsYiRePdhybGZ!FWp!dOWIZ9$WkaF>iHHaUn=ktPH0 z!wR)xwlHZ;XA>kwi@$}{xG2%;A2F8vS~So@X9D;elL;?*0`vV=ZYmH z;?ly<6%|=U1%x^vST4I(I;MQevyRFkLhc^Y)w z+ZFJ>yV*5w`bYY_jGFq`F!G!hExV(qZ8!8k4sAD3o|@a@?!4cR-5wG1C_KWe<^V>n zAdJGJhK!bh``7LUsZv(3rDL4){s(ONN&W-K%9B6wlm!ko;3E9I8Jqk5_SE$8(0vnl z@WiY&zms>)I07yU7kJtcCTLj!dFE9Sqk&J5`Q4DMLg!8mF#{?Z56$krJBZx9KQB;@ vXG8zcJ*Q{8o9A;;Hru`*DGQzoyt&@}?2!HR57QjRNe*tL7iVXeAKv}~s=9OY literal 0 HcmV?d00001 diff --git a/novawallet/Common/Extension/Foundation/TimeInterval+Time.swift b/novawallet/Common/Extension/Foundation/TimeInterval+Time.swift index 1d742c7c6f..61ed8ddced 100644 --- a/novawallet/Common/Extension/Foundation/TimeInterval+Time.swift +++ b/novawallet/Common/Extension/Foundation/TimeInterval+Time.swift @@ -18,6 +18,7 @@ extension TimeInterval { var daysFromSeconds: Int { Int(self / Self.secondsInDay) } var secondsFromDays: TimeInterval { self * Self.secondsInDay } var hoursFromSeconds: Int { Int(self / Self.secondsInHour) } + var secondsFromHours: TimeInterval { self * Self.secondsInHour } var intervalsInDay: Int { self > 0.0 ? Int(Self.secondsInDay / self) : 0 } func roundingUpToHour() -> TimeInterval { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 5f1c4404e7..770028b07f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -13,7 +13,8 @@ final class ReferendumVoteSetupPresenter { let balanceViewModelFactory: BalanceViewModelFactoryProtocol let referendumFormatter: LocalizableResource let chainAssetViewModelFactory: ChainAssetViewModelFactoryProtocol - let refendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol + let referendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol + let lockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol let logger: LoggerProtocol private var assetBalance: AssetBalance? @@ -34,7 +35,8 @@ final class ReferendumVoteSetupPresenter { balanceViewModelFactory: BalanceViewModelFactoryProtocol, referendumFormatter: LocalizableResource, chainAssetViewModelFactory: ChainAssetViewModelFactoryProtocol, - refendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol, + referendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol, + lockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol, interactor: ReferendumVoteSetupInteractorInputProtocol, wireframe: ReferendumVoteSetupWireframeProtocol, localizationManager: LocalizationManagerProtocol, @@ -45,7 +47,8 @@ final class ReferendumVoteSetupPresenter { self.balanceViewModelFactory = balanceViewModelFactory self.chainAssetViewModelFactory = chainAssetViewModelFactory self.referendumFormatter = referendumFormatter - self.refendumStringsViewModelFactory = refendumStringsViewModelFactory + self.referendumStringsViewModelFactory = referendumStringsViewModelFactory + self.lockChangeViewModelFactory = lockChangeViewModelFactory self.interactor = interactor self.wireframe = wireframe self.logger = logger @@ -153,6 +156,36 @@ final class ReferendumVoteSetupPresenter { view?.didReceiveAmount(inputViewModel: viewModel) } + private func updateLockedAmountView() { + guard + let lockDiff = lockDiff, + let viewModel = lockChangeViewModelFactory.createAmountViewModel( + from: lockDiff, + locale: selectedLocale + ) else { + return + } + + view?.didReceiveLockedAmount(viewModel: viewModel) + } + + private func updateLockedPeriodView() { + guard + let lockDiff = lockDiff, + let blockNumber = blockNumber, + let blockTime = blockTime, + let viewModel = lockChangeViewModelFactory.createPeriodViewModel( + from: lockDiff, + blockNumber: blockNumber, + blockTime: blockTime, + locale: selectedLocale + ) else { + return + } + + view?.didReceiveLockedPeriod(viewModel: viewModel) + } + private func updateVotesView() { guard let vote = deriveNewVote() else { return @@ -160,7 +193,7 @@ final class ReferendumVoteSetupPresenter { let voteValue = vote.voteAction.conviction.votes(for: vote.voteAction.amount) ?? 0 - let voteString = refendumStringsViewModelFactory.createVotes( + let voteString = referendumStringsViewModelFactory.createVotes( from: voteValue, chain: chain, locale: selectedLocale @@ -180,6 +213,8 @@ final class ReferendumVoteSetupPresenter { updateChainAssetViewModel() updateAmountPriceView() updateVotesView() + updateLockedAmountView() + updateLockedPeriodView() updateFeeView() } @@ -230,6 +265,8 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { refreshFee() refreshLockDiff() + + updateVotesView() updateAmountPriceView() } @@ -240,6 +277,8 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { refreshFee() refreshLockDiff() + + updateVotesView() updateAmountPriceView() } @@ -256,18 +295,17 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { refreshLockDiff() } - func proceedNay() { - - } - - func proceedAye() { + func proceedNay() {} - } + func proceedAye() {} } extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProtocol { func didReceiveLockStateDiff(_ diff: GovernanceLockStateDiff) { lockDiff = diff + + updateLockedAmountView() + updateLockedPeriodView() } func didReceiveAccountVotes( @@ -278,9 +316,19 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto refreshLockDiff() } - func didReceiveBlockNumber(_: BlockNumber) {} + func didReceiveBlockNumber(_ blockNumber: BlockNumber) { + self.blockNumber = blockNumber + + updateLockedAmountView() + updateLockedPeriodView() + } + + func didReceiveBlockTime(_ blockTime: BlockTime) { + self.blockTime = blockTime - func didReceiveBlockTime(_: BlockTime) {} + updateLockedAmountView() + updateLockedPeriodView() + } func didReceiveError(_ error: ReferendumVoteSetupInteractorError) { logger.error("Did receive setup error: \(error)") diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index acf66799b7..c66f24ff6d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -10,6 +10,8 @@ protocol ReferendumVoteSetupViewProtocol: ControllerBackedProtocol { func didReceiveAmountInputPrice(viewModel: String?) func didReceiveVotes(viewModel: String) func didReceiveConviction(viewModel: UInt) + func didReceiveLockedAmount(viewModel: ReferendumLockTransitionViewModel) + func didReceiveLockedPeriod(viewModel: ReferendumLockTransitionViewModel) } protocol ReferendumVoteSetupPresenterProtocol: AnyObject { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift index 2a59226bba..8cc2dd52b5 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -166,6 +166,14 @@ extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol { rootView.convictionView.slider.value = viewModel } } + + func didReceiveLockedAmount(viewModel: ReferendumLockTransitionViewModel) { + rootView.bindLockAmount(viewModel: viewModel) + } + + func didReceiveLockedPeriod(viewModel: ReferendumLockTransitionViewModel) { + rootView.bindLockPeriod(viewModel: viewModel) + } } extension ReferendumVoteSetupViewController: AmountInputAccessoryViewDelegate { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index f3ce6440c1..93b1b62624 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -32,12 +32,17 @@ struct ReferendumVoteSetupViewFactory { let networkViewModelFactory = NetworkViewModelFactory() let chainAssetViewModelFactory = ChainAssetViewModelFactory(networkViewModelFactory: networkViewModelFactory) + let lockChangeViewModelFactory = ReferendumLockChangeViewModelFactory(assetDisplayInfo: assetDisplayInfo) + let referendumStringsViewModelFactory = ReferendumDisplayStringFactory() + let presenter = ReferendumVoteSetupPresenter( chain: chain, referendumIndex: referendum, balanceViewModelFactory: balanceViewModelFactory, referendumFormatter: NumberFormatter.index.localizableResource(), chainAssetViewModelFactory: chainAssetViewModelFactory, + referendumStringsViewModelFactory: referendumStringsViewModelFactory, + lockChangeViewModelFactory: lockChangeViewModelFactory, interactor: interactor, wireframe: wireframe, localizationManager: localizationManager, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index 90059dff52..dc0f0979d6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -44,7 +44,7 @@ final class ReferendumVoteSetupViewLayout: UIView { let lockedAmountView: GenericTitleValueView = { let view = ReferendumVoteSetupViewLayout.createMultiValueView() - view.titleView.imageView.image = R.image.iconLock()?.tinted(with: R.color.colorWhite48()!) + view.titleView.imageView.image = R.image.iconGovAmountLock() return view }() @@ -54,7 +54,7 @@ final class ReferendumVoteSetupViewLayout: UIView { let lockedPeriodView: GenericTitleValueView = { let view = ReferendumVoteSetupViewLayout.createMultiValueView() - view.titleView.imageView.image = R.image.iconPending()?.tinted(with: R.color.colorWhite48()!) + view.titleView.imageView.image = R.image.iconGovPeriodLock() return view }() @@ -79,6 +79,40 @@ final class ReferendumVoteSetupViewLayout: UIView { fatalError("init(coder:) has not been implemented") } + func bindLockAmount(viewModel: ReferendumLockTransitionViewModel) { + bindLockTrasition(for: viewModel, view: lockedAmountView) + + setNeedsLayout() + } + + func bindLockPeriod(viewModel: ReferendumLockTransitionViewModel) { + bindLockTrasition(for: viewModel, view: lockedPeriodView) + + setNeedsLayout() + } + + private func bindLockTrasition( + for viewModel: ReferendumLockTransitionViewModel, + view: GenericTitleValueView + ) { + let viewTop = view.valueView.fView + viewTop.fView.detailsLabel.text = viewModel.fromValue + viewTop.sView.text = viewModel.toValue + + let viewBottom = view.valueView.sView + + if let change = viewModel.change { + viewBottom.isHidden = false + + viewBottom.detailsLabel.text = change.value + + let icon = change.isIncrease ? R.image.iconAmountInc() : R.image.iconAmountDec() + viewBottom.imageView.image = icon + } else { + viewBottom.isHidden = true + } + } + private func setupLayout() { addSubview(nayButton) nayButton.snp.makeConstraints { make in @@ -158,6 +192,7 @@ final class ReferendumVoteSetupViewLayout: UIView { mappingView.fView.spacing = 4.0 mappingView.fView.detailsLabel.textColor = R.color.colorTransparentText() mappingView.fView.detailsLabel.font = .regularFootnote + mappingView.fView.imageView.image = R.image.iconGovLockTransition() mappingView.sView.textColor = R.color.colorWhite() mappingView.sView.font = .regularFootnote diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModel.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModel.swift new file mode 100644 index 0000000000..5c17f1d2a8 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModel.swift @@ -0,0 +1,12 @@ +import Foundation + +struct ReferendumLockTransitionViewModel { + struct Change { + let isIncrease: Bool + let value: String + } + + let fromValue: String + let toValue: String + let change: Change? +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift new file mode 100644 index 0000000000..987f641818 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift @@ -0,0 +1,127 @@ +import Foundation +import SoraFoundation + +protocol ReferendumLockChangeViewModelFactoryProtocol { + func createAmountViewModel( + from diff: GovernanceLockStateDiff, + locale: Locale + ) -> ReferendumLockTransitionViewModel? + + func createPeriodViewModel( + from diff: GovernanceLockStateDiff, + blockNumber: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumLockTransitionViewModel? +} + +final class ReferendumLockChangeViewModelFactory { + let balanceFormatter: LocalizableResource + let amountFormatter: LocalizableResource + let assetDisplayInfo: AssetBalanceDisplayInfo + + init( + assetDisplayInfo: AssetBalanceDisplayInfo, + assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol = AssetBalanceFormatterFactory() + ) { + balanceFormatter = assetBalanceFormatterFactory.createTokenFormatter(for: assetDisplayInfo) + amountFormatter = assetBalanceFormatterFactory.createDisplayFormatter(for: assetDisplayInfo) + self.assetDisplayInfo = assetDisplayInfo + } +} + +extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol { + func createAmountViewModel( + from diff: GovernanceLockStateDiff, + locale: Locale + ) -> ReferendumLockTransitionViewModel? { + guard + let fromAmountDecimal = Decimal.fromSubstrateAmount( + diff.before.maxLockedAmount, + precision: assetDisplayInfo.assetPrecision + ), + let fromAmountString = amountFormatter.value(for: locale).stringFromDecimal(fromAmountDecimal) else { + return nil + } + + let toAmountString: String + let change: ReferendumLockTransitionViewModel.Change? + + let balanceFormatter = balanceFormatter.value(for: locale) + + if let toState = diff.after { + guard + let toAmountDecimal = Decimal.fromSubstrateAmount( + toState.maxLockedAmount, + precision: assetDisplayInfo.assetPrecision + ) else { + return nil + } + + toAmountString = balanceFormatter.stringFromDecimal(toAmountDecimal) ?? "" + + if toAmountDecimal > fromAmountDecimal { + let changeAmountString = balanceFormatter.stringFromDecimal(toAmountDecimal - fromAmountDecimal) ?? "" + change = .init(isIncrease: true, value: changeAmountString) + } else if toAmountDecimal < fromAmountDecimal { + let changeAmountString = balanceFormatter.stringFromDecimal(fromAmountDecimal - toAmountDecimal) ?? "" + change = .init(isIncrease: false, value: changeAmountString) + } else { + change = nil + } + + } else { + toAmountString = balanceFormatter.stringFromDecimal(fromAmountDecimal) ?? "" + change = nil + } + + return .init(fromValue: fromAmountString, toValue: toAmountString, change: change) + } + + func createPeriodViewModel( + from diff: GovernanceLockStateDiff, + blockNumber: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumLockTransitionViewModel? { + let fromBlock = max(diff.before.lockedUntil ?? blockNumber, blockNumber) + + let fromPeriod = blockNumber.secondsTo(block: fromBlock, blockDuration: blockTime) + let fromPeriodString = fromPeriod.localizedDaysHours(for: locale) + + let toPeriodString: String + let change: ReferendumLockTransitionViewModel.Change? + + if let toState = diff.after { + let toBlock = max(toState.lockedUntil ?? blockNumber, blockNumber) + let toPeriod = blockNumber.secondsTo(block: toBlock, blockDuration: blockTime) + + toPeriodString = toPeriod.localizedDaysHours(for: locale) + + if fromPeriod < toPeriod, (toPeriod - fromPeriod).hoursFromSeconds > 0 { + change = .init( + isIncrease: true, + value: R.string.localizable.commonMaximum( + (toPeriod - fromPeriod).localizedDaysHours(for: locale), + preferredLanguages: locale.rLanguages + ) + ) + } else if fromPeriod > toPeriod, (fromPeriod - toPeriod).hoursFromSeconds > 0 { + change = .init( + isIncrease: false, + value: R.string.localizable.commonMaximum( + (fromPeriod - toPeriod).localizedDaysHours(for: locale), + preferredLanguages: locale.rLanguages + ) + ) + } else { + change = nil + } + } else { + toPeriodString = fromPeriodString + change = nil + } + + return .init(fromValue: fromPeriodString, toValue: toPeriodString, change: change) + } +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift index 3e199e36a4..eb0b0df67f 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift @@ -15,7 +15,7 @@ protocol ReferendumDisplayStringFactoryProtocol { final class ReferendumDisplayStringFactory: ReferendumDisplayStringFactoryProtocol { let formatterFactory: AssetBalanceFormatterFactoryProtocol - init(formatterFactory: AssetBalanceFormatterFactoryProtocol) { + init(formatterFactory: AssetBalanceFormatterFactoryProtocol = AssetBalanceFormatterFactory()) { self.formatterFactory = formatterFactory } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 0d4c8916cf..443519fd2c 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1032,3 +1032,4 @@ "gov.vote.setup.hint" = "After locking period don’t forget to unlock your tokens"; "gov.vote.setup.title.format" = "Vote for Referendum %@"; "common.available.prefix" = "Available:"; +"common.maximum" = "%@ maximum"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 4234651efb..0ca1da76a8 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1033,3 +1033,4 @@ "gov.vote.setup.hint" = "После окончания периода блокировки не забудьте забрать токены"; "gov.vote.setup.title.format" = "Голосование за референдум %@"; "common.available.prefix" = "Доступно:"; +"common.maximum" = "%@ максимум"; From 2b99395e0751e1f8ae44c01e9870a5254cf59575 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 20 Oct 2022 21:13:34 +0500 Subject: [PATCH 071/229] adopt ui to recent version --- .../iconAmountDec.imageset/iconAmountDec.pdf | Bin 2117 -> 1534 bytes .../TimeInterval+Localization.swift | 11 ++++++++ .../Common/View/DiscreteGradientSlider.swift | 4 +-- .../ReferendumVoteSetupInteractor.swift | 2 ++ .../ReferendumVoteSetupPresenter.swift | 24 ++--------------- .../ReferendumVoteSetupProtocols.swift | 1 - .../ReferendumVoteSetupViewController.swift | 9 ------- .../ReferendumVoteSetupViewLayout.swift | 25 +++++++----------- .../View/ReferendumConvictionView.swift | 4 ++- ...ReferendumLockChangeViewModelFactory.swift | 8 +++--- novawallet/en.lproj/Localizable.strings | 2 +- novawallet/ru.lproj/Localizable.strings | 2 +- 12 files changed, 35 insertions(+), 57 deletions(-) diff --git a/novawallet/Assets.xcassets/iconAmountDec.imageset/iconAmountDec.pdf b/novawallet/Assets.xcassets/iconAmountDec.imageset/iconAmountDec.pdf index 932ad2652a82b09b4d7b235e3331edabb1ca91cc..534e496d82786120b88a932cf511c882b20c998c 100644 GIT binary patch literal 1534 zcmZvcO>fjN5Qgvm6?3W7BGvKthg4OfTZ#}M%9dNjA!OZl(QX1siVDA;u{W{PLJq6! zW6yZzeKS6~zPvi+)DpshLHF%D0XRE@^K%l~P5ev5l2;!>dp|yaM7WN-hOrOzo>Z6N z*R~1kw->OwS^jGV@{@4N(gSRMIn8f*P0eeP8pVvz(Ci7LTzGCQMrtQ83FQ4l(-KLw z*IqhY7FIZCV2{jk&%BO@Y2~Z{MY&_1VaYW!(AIfm z4kN6EOfadJUNgvXiYm^%!MZV*VP08{M;qb2i@Suf1{+xrCY0t3Nsh}JaH_QBieU|m zdW(JdvM(~Lg_N>nV^n&kg<2BSO&V9?8WLqcG?dFPDEEk>A0o37&3}~Mk%wr{VJ9}M zjWj&zpFD~6N@lFn*u&(BLB^c3CN3sVV!fFpPk4#To=B80<&Sz~2T*vcB#NAgqe57x z-0X?OC8e}8vUp;U86%yIyCzQ-Wb$MYmp#!`dCu@-n?3QY~2KB#tMOyNi#95sNah}>ZpoeL8UgcRE;_1N|PH)g=B(cu;6y)7Y#2LfFp6%k?;%D<535{M( zXzc6lF7zb2_wEwqI3BuvIDzBs=HwtsweGqRV#7(`>Sp^VVD;&yuKO{y!zCBw=;+O- FtG^Q^NQwXe literal 2117 zcmZuy+iu%N5PjdTm=~i`(Jc3VDGUR)WEDXg#F2|Uj(MgKGe$b=KvKs&^Cm~M*IxQlToqnrtTYZZ#l6Bg*pWa} zYwJ8HikXBJkV9H1hm=yJqLLZwkU3_Pp5b#0WX@R|c3CZ?lsV$9R%7xMm%3o7Fx+s4 zEG%V0X!xXk9zK1+na8X6>-$p;#a;PWN8oL} z*_Jo$GkiiK=OfI`1f5n>rgh!7hpwu72&c+ArdzblP&fF-aHLG&UD+W9IzrjO6QFb; z6>qj1qza*eHB9eWvemdf}?&~?s zwww8}DaE>N2M7g^4KD7tKWbz@p44SGjOB321-ZDmeYcwYkh=lCbv|XUa^%jP*1REuiC3-qC|mqKQmYCkw`p!sw3>eAl&` zLsfS$+n3e5d-zay{kCm@3##Dr?B=lDZ9wpq^`GbP{(znM0r=$`i9HX$!S&M;OHD5T3dgEU>U3!@Oz(J String { + let days = daysFromSeconds + let hours = (self - TimeInterval(days).secondsFromDays).hoursFromSeconds + + guard days > 0 || hours > 0 else { + return R.string.localizable.commonDaysFormat(format: 0, preferredLanguages: locale.rLanguages) + } + + return localizedDaysHours(for: locale) + } + func localizedDaysOrTime(for locale: Locale) -> String? { let days = daysFromSeconds diff --git a/novawallet/Common/View/DiscreteGradientSlider.swift b/novawallet/Common/View/DiscreteGradientSlider.swift index ed8ec10b67..aba1c8b1bb 100644 --- a/novawallet/Common/View/DiscreteGradientSlider.swift +++ b/novawallet/Common/View/DiscreteGradientSlider.swift @@ -47,7 +47,7 @@ class DiscreteGradientSlider: UIControl { } } - var verticalSpacing: CGFloat = 14 { + var verticalSpacing: CGFloat = 5.0 { didSet { invalidateIntrinsicContentSize() setNeedsLayout() @@ -71,7 +71,7 @@ class DiscreteGradientSlider: UIControl { } } - var contentInsets = UIEdgeInsets(top: 16.0, left: 0.0, bottom: 16.0, right: 0.0) { + var contentInsets: UIEdgeInsets = .zero { didSet { invalidateIntrinsicContentSize() setNeedsLayout() diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift index ecd60fb2c7..d886eb1bf2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift @@ -137,6 +137,8 @@ final class ReferendumVoteSetupInteractor: ReferendumVoteInteractor, AnyCancella private func makeSubscriptions() { clearAndSubscribeBlockNumber() + + subscribeAccountVotes() } override func setup() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 770028b07f..5c5ed1ff51 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -70,25 +70,6 @@ final class ReferendumVoteSetupPresenter { return balance - fee } - private func updateFeeView() { - let optAssetInfo = chain.utilityAssets().first?.displayInfo - if let fee = fee, let assetInfo = optAssetInfo { - let feeDecimal = Decimal.fromSubstrateAmount( - fee, - precision: assetInfo.assetPrecision - ) ?? 0.0 - - let viewModel = balanceViewModelFactory.balanceFromPrice( - feeDecimal, - priceData: priceData - ).value(for: selectedLocale) - - view?.didReceiveFee(viewModel: viewModel) - } else { - view?.didReceiveFee(viewModel: nil) - } - } - private func updateAvailableBalanceView() { if let assetBalance = assetBalance { let precision = chain.utilityAsset()?.displayInfo.assetPrecision ?? 0 @@ -215,7 +196,6 @@ final class ReferendumVoteSetupPresenter { updateVotesView() updateLockedAmountView() updateLockedPeriodView() - updateFeeView() } private func deriveNewVote() -> ReferendumNewVote? { @@ -319,6 +299,8 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto func didReceiveBlockNumber(_ blockNumber: BlockNumber) { self.blockNumber = blockNumber + interactor.refreshBlockTime() + updateLockedAmountView() updateLockedPeriodView() } @@ -363,7 +345,6 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto priceData = price updateAmountPriceView() - updateFeeView() } func didReceiveVotingReferendum(_ referendum: ReferendumLocal) { @@ -373,7 +354,6 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto func didReceiveFee(_ fee: BigUInt) { self.fee = fee - updateFeeView() updateAmountPriceView() provideAmountInputViewModelIfRate() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index c66f24ff6d..2242819c2d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -6,7 +6,6 @@ protocol ReferendumVoteSetupViewProtocol: ControllerBackedProtocol { func didReceiveBalance(viewModel: String) func didReceiveInputChainAsset(viewModel: ChainAssetViewModel) func didReceiveAmount(inputViewModel: AmountInputViewModelProtocol) - func didReceiveFee(viewModel: BalanceViewModelProtocol?) func didReceiveAmountInputPrice(viewModel: String?) func didReceiveVotes(viewModel: String) func didReceiveConviction(viewModel: UInt) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift index 8cc2dd52b5..5816b4203a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -83,11 +83,6 @@ final class ReferendumVoteSetupViewController: UIViewController, ViewHolder { rootView.lockAmountTitleLabel.text = R.string.localizable.commonGovLock(preferredLanguages: languages) rootView.lockPeriodTitleLabel.text = R.string.localizable.commonLockingPeriod(preferredLanguages: languages) - rootView.feeView.locale = selectedLocale - - let hint = R.string.localizable.govVoteSetupHint(preferredLanguages: languages) - rootView.hintListView.bind(texts: [hint]) - rootView.nayButton.imageWithTitleView?.title = R.string.localizable.governanceNay(preferredLanguages: languages) rootView.ayeButton.imageWithTitleView?.title = R.string.localizable.governanceAye(preferredLanguages: languages) @@ -149,10 +144,6 @@ extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol { rootView.amountInputView.bind(inputViewModel: inputViewModel) } - func didReceiveFee(viewModel: BalanceViewModelProtocol?) { - rootView.feeView.bind(viewModel: viewModel) - } - func didReceiveAmountInputPrice(viewModel: String?) { rootView.amountInputView.bind(priceViewModel: viewModel) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index dc0f0979d6..6ad9cc4d94 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -28,7 +28,7 @@ final class ReferendumVoteSetupViewLayout: UIView { let titleLabel: UILabel = .create { view in view.textColor = R.color.colorWhite() - view.font = .title2 + view.font = .boldTitle2 view.numberOfLines = 0 } @@ -58,14 +58,6 @@ final class ReferendumVoteSetupViewLayout: UIView { return view }() - let feeView: NetworkFeeView = { - let view = UIFactory.default.createNetwork26FeeView() - view.verticalOffset = 13.0 - return view - }() - - let hintListView = HintListView() - override init(frame: CGRect) { super.init(frame: frame) @@ -138,7 +130,7 @@ final class ReferendumVoteSetupViewLayout: UIView { containerView.stackView.addArrangedSubview(titleLabel) - containerView.stackView.setCustomSpacing(16.0, after: titleLabel) + containerView.stackView.setCustomSpacing(12.0, after: titleLabel) containerView.stackView.addArrangedSubview(amountView) containerView.stackView.addArrangedSubview(amountInputView) @@ -159,6 +151,8 @@ final class ReferendumVoteSetupViewLayout: UIView { containerView.stackView.addArrangedSubview(lockedAmountView) + containerView.stackView.setCustomSpacing(10.0, after: lockedAmountView) + lockedAmountView.snp.makeConstraints { make in make.height.equalTo(34.0) } @@ -168,12 +162,6 @@ final class ReferendumVoteSetupViewLayout: UIView { lockedPeriodView.snp.makeConstraints { make in make.height.equalTo(34.0) } - - containerView.stackView.addArrangedSubview(feeView) - - containerView.stackView.setCustomSpacing(16.0, after: feeView) - - containerView.stackView.addArrangedSubview(hintListView) } static func createMultiValueView() -> GenericTitleValueView { @@ -183,15 +171,19 @@ final class ReferendumVoteSetupViewLayout: UIView { view.titleView.iconWidth = 16.0 view.titleView.detailsLabel.textColor = R.color.colorTransparentText() view.titleView.detailsLabel.font = .regularFootnote + view.titleView.detailsLabel.numberOfLines = 1 view.valueView.setVerticalAndSpacing(0.0) + view.valueView.stackView.alignment = .trailing let mappingView = view.valueView.fView mappingView.setHorizontalAndSpacing(4.0) mappingView.fView.iconWidth = 12.0 mappingView.fView.spacing = 4.0 + mappingView.fView.mode = .detailsIcon mappingView.fView.detailsLabel.textColor = R.color.colorTransparentText() mappingView.fView.detailsLabel.font = .regularFootnote + mappingView.fView.detailsLabel.numberOfLines = 1 mappingView.fView.imageView.image = R.image.iconGovLockTransition() mappingView.sView.textColor = R.color.colorWhite() mappingView.sView.font = .regularFootnote @@ -201,6 +193,7 @@ final class ReferendumVoteSetupViewLayout: UIView { changesView.spacing = 0.0 changesView.detailsLabel.textColor = R.color.colorNovaBlue() changesView.detailsLabel.font = .caption1 + changesView.detailsLabel.numberOfLines = 1 return view } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift index e253734c41..d6e09a0e52 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/View/ReferendumConvictionView.swift @@ -24,6 +24,7 @@ final class ReferendumConvictionView: UIView { let votesView: UILabel = .create { view in view.textColor = R.color.colorWhite() view.font = .boldTitle2 + view.textAlignment = .center } override init(frame: CGRect) { @@ -58,7 +59,8 @@ final class ReferendumConvictionView: UIView { ]) stackView.spacing = 0 - stackView.setCustomSpacing(12.0, after: titleLabel) + stackView.setCustomSpacing(13.0, after: titleLabel) + stackView.setCustomSpacing(14.0, after: slider) stackView.setCustomSpacing(12.0, after: separatorView) backgroundView.addSubview(stackView) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift index 987f641818..cce0882898 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift @@ -87,7 +87,7 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac let fromBlock = max(diff.before.lockedUntil ?? blockNumber, blockNumber) let fromPeriod = blockNumber.secondsTo(block: fromBlock, blockDuration: blockTime) - let fromPeriodString = fromPeriod.localizedDaysHours(for: locale) + let fromPeriodString = fromPeriod.localizedDaysHoursIncludingZero(for: locale) let toPeriodString: String let change: ReferendumLockTransitionViewModel.Change? @@ -96,13 +96,13 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac let toBlock = max(toState.lockedUntil ?? blockNumber, blockNumber) let toPeriod = blockNumber.secondsTo(block: toBlock, blockDuration: blockTime) - toPeriodString = toPeriod.localizedDaysHours(for: locale) + toPeriodString = toPeriod.localizedDaysHoursIncludingZero(for: locale) if fromPeriod < toPeriod, (toPeriod - fromPeriod).hoursFromSeconds > 0 { change = .init( isIncrease: true, value: R.string.localizable.commonMaximum( - (toPeriod - fromPeriod).localizedDaysHours(for: locale), + (toPeriod - fromPeriod).localizedDaysHoursIncludingZero(for: locale), preferredLanguages: locale.rLanguages ) ) @@ -110,7 +110,7 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac change = .init( isIncrease: false, value: R.string.localizable.commonMaximum( - (fromPeriod - toPeriod).localizedDaysHours(for: locale), + (fromPeriod - toPeriod).localizedDaysHoursIncludingZero(for: locale), preferredLanguages: locale.rLanguages ) ) diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 443519fd2c..5c49eb1307 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1030,6 +1030,6 @@ "common.gov.lock" = "Governance lock"; "common.locking.period" = "Locking period"; "gov.vote.setup.hint" = "After locking period don’t forget to unlock your tokens"; -"gov.vote.setup.title.format" = "Vote for Referendum %@"; +"gov.vote.setup.title.format" = "Vote for %@"; "common.available.prefix" = "Available:"; "common.maximum" = "%@ maximum"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 0ca1da76a8..985f5b46da 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1031,6 +1031,6 @@ "common.gov.lock" = "Блокировка в голосовании"; "common.locking.period" = "Период блокировки"; "gov.vote.setup.hint" = "После окончания периода блокировки не забудьте забрать токены"; -"gov.vote.setup.title.format" = "Голосование за референдум %@"; +"gov.vote.setup.title.format" = "Голосование за %@"; "common.available.prefix" = "Доступно:"; "common.maximum" = "%@ максимум"; From 32bdc60bcb6d5557d529ef144e1fd7bfd9b08857 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 20 Oct 2022 21:28:42 +0500 Subject: [PATCH 072/229] fix tests --- novawalletIntegrationTests/Gov2OperationFactoryTests.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift index 476170bfbd..39c8cbbcc6 100644 --- a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift +++ b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift @@ -60,7 +60,8 @@ class Gov2OperationFactoryTests: XCTestCase { let wrapper = operationFactory.fetchAccountVotesWrapper( for: accountId, from: connection, - runtimeProvider: runtimeProvider + runtimeProvider: runtimeProvider, + blockHash: nil ) operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: true) @@ -85,7 +86,7 @@ class Gov2OperationFactoryTests: XCTestCase { let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) let wrapper = operationFactory.fetchVotersWrapper( - for: referendumIndex, + for: ReferendumIdLocal(referendumIndex), from: connection, runtimeProvider: runtimeProvider ) From ffd8b0a4de23b5004ff66583aa1d9162afc3a545 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 21 Oct 2022 08:10:35 +0300 Subject: [PATCH 073/229] added cell title --- .../ReferendumDetailsProtocols.swift | 2 +- .../ReferendumDetailsViewController.swift | 8 ++--- .../ReferendumDetailsViewLayout.swift | 31 +++++++++++++++++-- .../View/Rows/FullDetailsRow.swift | 2 +- .../View/Rows/ReferendumDAppCellView.swift | 2 +- .../View/Rows/RequestedAmountRow.swift | 2 +- .../View/Rows/RoundedView+Styles.swift | 6 ++-- .../View/Rows/TimelineRow.swift | 5 ++- .../View/Rows/VotingDetailsRow.swift | 2 +- .../View/Rows/YourVoteRow.swift | 2 +- 10 files changed, 43 insertions(+), 19 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index a1a938cc27..8ae0947db2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -1,7 +1,7 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { func didReceive(votingDetails: ReferendumVotingStatusDetailsView.Model) func didReceive(dAppModels: [ReferendumDAppView.Model]) - func didReceive(timelineModel: ReferendumTimelineView.Model) + func didReceive(timelineModel: ReferendumTimelineView.Model?) func didReceive(titleModel: ReferendumDetailsTitleView.Model) func didReceive(yourVoteModel: YourVoteRow.Model?) func didReceive(requestedAmount: RequestedAmountRow.Model?) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index e3cab24e6a..96be13083f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -84,7 +84,7 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { let iconViewModel = optIcon.map { DrawableIconViewModel(icon: $0) } didReceive(trackTagsModel: .init( - titleIcon: .init(title: "main agenda", icon: nil), + titleIcon: .init(title: "main agenda".uppercased(), icon: nil), referendumNumber: "224" )) didReceive(titleModel: .init( @@ -123,11 +123,11 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { } func didReceive(dAppModels: [ReferendumDAppView.Model]) { - rootView.setDApps(models: dAppModels) + rootView.setDApps(title: "Use Nova DApp browser", models: dAppModels) } - func didReceive(timelineModel: ReferendumTimelineView.Model) { - rootView.timelineRow.bind(viewModel: timelineModel) + func didReceive(timelineModel: ReferendumTimelineView.Model?) { + rootView.setTimeline(title: "Timeline", model: timelineModel) } func didReceive(titleModel: ReferendumDetailsTitleView.Model) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 3308738974..741f5cafe8 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -12,7 +12,7 @@ final class ReferendumDetailsViewLayout: UIView { let titleView = ReferendumDetailsTitleView() let votingDetailsRow = VotingDetailsRow(frame: .zero) let dAppsTableView = StackTableView() - let timelineRow = TimelineRow(frame: .zero) + var timelineTableView = StackTableView() var yourVoteRow: YourVoteRow? var requestedAmountRow: RequestedAmountRow? @@ -42,13 +42,30 @@ final class ReferendumDetailsViewLayout: UIView { containerView.stackView.addArrangedSubview(votingDetailsRow) containerView.stackView.addArrangedSubview(dAppsTableView) - containerView.stackView.addArrangedSubview(timelineRow) + containerView.stackView.addArrangedSubview(timelineTableView) containerView.stackView.addArrangedSubview(fullDetailsView) + + timelineTableView.apply(style: .cellWithoutHighlighting) + dAppsTableView.apply(style: .cellWithoutHighlighting) } - func setDApps(models: [ReferendumDAppView.Model]) { + func setTimeline(title: String, model: ReferendumTimelineView.Model?) { + timelineTableView.clear() + guard let model = model else { + return + } + let headerView = createHeader(with: title) + let timelineRow = TimelineRow(frame: .zero) + timelineRow.bind(viewModel: model) + timelineTableView.stackView.addArrangedSubview(headerView) + timelineTableView.stackView.addArrangedSubview(timelineRow) + } + + func setDApps(title: String, models: [ReferendumDAppView.Model]) { dAppsTableView.clear() + let headerView = createHeader(with: title) + dAppsTableView.stackView.addArrangedSubview(headerView) for model in models { let dAppView = ReferendumDAppCellView(frame: .zero) dAppView.rowContentView.bind(viewModel: model) @@ -81,4 +98,12 @@ final class ReferendumDetailsViewLayout: UIView { } requestedAmountRow?.bind(viewModel: requestedAmountViewModel) } + + private func createHeader(with text: String) -> StackTableHeaderCell { + let headerView = StackTableHeaderCell() + headerView.titleLabel.apply(style: .footnoteWhite64) + headerView.titleLabel.text = text + headerView.contentInsets = .init(top: 16, left: 16, bottom: 8, right: 16) + return headerView + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift index f5ed70c1ee..4b4e2a640d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift @@ -8,7 +8,7 @@ final class FullDetailsRow: RowView> rowContentView.titleView.apply(style: .rowLink) rowContentView.titleView.textAlignment = .left rowContentView.valueView.image = R.image.iconChevronRight() - roundedBackgroundView.apply(style: .roundedSelectableCell) + roundedBackgroundView.apply(style: .roundedLightCell) preferredHeight = 52 contentInsets = .init(top: 14, left: 16, bottom: 14, right: 16) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift index 24c606a583..3f055786f4 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift @@ -4,8 +4,8 @@ final class ReferendumDAppCellView: RowView, StackTableViewC override init(frame: CGRect) { super.init(frame: frame) - roundedBackgroundView.apply(style: .roundedSelectableCell) backgroundColor = .clear preferredHeight = 64 + contentInsets = .init(top: 8, left: 16, bottom: 8, right: 16) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift index 01f29e04c4..290a75c0fd 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift @@ -15,7 +15,7 @@ final class RequestedAmountRow: RowView> { rowContentView.valueBottom.apply(style: .accentAmount) rowContentView.valueBottom.valueTop.textAlignment = .left rowContentView.valueBottom.valueBottom.textAlignment = .left - roundedBackgroundView.apply(style: .roundedView) + roundedBackgroundView.apply(style: .cellWithoutHighlighting) contentInsets = .init(top: 16, left: 16, bottom: 16, right: 16) backgroundColor = .clear isUserInteractionEnabled = false diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RoundedView+Styles.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RoundedView+Styles.swift index ea5b2399c5..428cb5b0a3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RoundedView+Styles.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RoundedView+Styles.swift @@ -2,7 +2,7 @@ import UIKit import SoraUI extension RoundedView.Style { - static let roundedSelectableCell = RoundedView.Style( + static let roundedLightCell = RoundedView.Style( shadowOpacity: 0, strokeWidth: 0, strokeColor: .clear, @@ -11,13 +11,13 @@ extension RoundedView.Style { highlightedFillColor: R.color.colorAccentSelected()!, rounding: .init(radius: 12, corners: .allCorners) ) - static let roundedView = RoundedView.Style( + static let cellWithoutHighlighting = RoundedView.Style( shadowOpacity: 0, strokeWidth: 0, strokeColor: .clear, highlightedStrokeColor: .clear, fillColor: R.color.colorWhite8()!, - highlightedFillColor: .clear, + highlightedFillColor: R.color.colorWhite8()!, rounding: .init(radius: 12, corners: .allCorners) ) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift index 13e24af0db..21a7f66923 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift @@ -1,12 +1,11 @@ import UIKit -final class TimelineRow: RowView { +final class TimelineRow: RowView, StackTableViewCellProtocol { override init(frame: CGRect) { super.init(frame: frame) isUserInteractionEnabled = false - roundedBackgroundView.apply(style: .roundedView) - contentInsets = .init(top: 16, left: 16, bottom: 0, right: 16) + contentInsets = .init(top: 8, left: 16, bottom: 0, right: 16) backgroundColor = .clear } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift index 8f00e2c04a..d004302afe 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/VotingDetailsRow.swift @@ -5,7 +5,7 @@ final class VotingDetailsRow: RowView { super.init(frame: frame) contentInsets = .zero - roundedBackgroundView.apply(style: .roundedView) + roundedBackgroundView.apply(style: .cellWithoutHighlighting) backgroundColor = .clear } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift index c8102d32dc..102a52bb8d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift @@ -10,7 +10,7 @@ final class YourVoteRow: RowView Date: Fri, 21 Oct 2022 08:20:27 +0300 Subject: [PATCH 074/229] added localizable strings, move title to function signature --- .../ReferendumDetailsProtocols.swift | 4 +- .../ReferendumDetailsViewController.swift | 38 +++++++++++-------- novawallet/en.lproj/Localizable.strings | 2 + novawallet/ru.lproj/Localizable.strings | 2 + 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 8ae0947db2..06c4e9f1c9 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -1,7 +1,7 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { func didReceive(votingDetails: ReferendumVotingStatusDetailsView.Model) - func didReceive(dAppModels: [ReferendumDAppView.Model]) - func didReceive(timelineModel: ReferendumTimelineView.Model?) + func didReceive(title: String, dAppModels: [ReferendumDAppView.Model]) + func didReceive(title: String, timelineModel: ReferendumTimelineView.Model?) func didReceive(titleModel: ReferendumDetailsTitleView.Model) func didReceive(yourVoteModel: YourVoteRow.Model?) func didReceive(requestedAmount: RequestedAmountRow.Model?) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 96be13083f..9433447c39 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -60,13 +60,16 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { )) let iconUrl = URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/chains/white/Polkadot.svg")! - didReceive(dAppModels: [ - .init( - icon: RemoteImageViewModel(url: iconUrl), - title: "Polkassembly", - subtitle: "Comment and react" - ) - ]) + didReceive( + title: "Use Nova DApp browser", + dAppModels: [ + .init( + icon: RemoteImageViewModel(url: iconUrl), + title: "Polkassembly", + subtitle: "Comment and react" + ) + ] + ) let metaAccount = MetaAccountModel( metaId: UUID().uuidString, @@ -97,11 +100,14 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { ) ) - didReceive(timelineModel: .init(title: "Timeline", statuses: [ - .init(title: "One", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), - .init(title: "Two", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), - .init(title: "Three", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) - ])) + didReceive( + title: "Timeline", + timelineModel: .init(title: "Timeline", statuses: [ + .init(title: "One", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), + .init(title: "Two", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), + .init(title: "Three", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) + ]) + ) rootView.fullDetailsView.bind(title: "Full details") @@ -122,12 +128,12 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { rootView.votingDetailsRow.bind(viewModel: votingDetails) } - func didReceive(dAppModels: [ReferendumDAppView.Model]) { - rootView.setDApps(title: "Use Nova DApp browser", models: dAppModels) + func didReceive(title: String, dAppModels: [ReferendumDAppView.Model]) { + rootView.setDApps(title: title, models: dAppModels) } - func didReceive(timelineModel: ReferendumTimelineView.Model?) { - rootView.setTimeline(title: "Timeline", model: timelineModel) + func didReceive(title: String, timelineModel: ReferendumTimelineView.Model?) { + rootView.setTimeline(title: title, model: timelineModel) } func didReceive(titleModel: ReferendumDetailsTitleView.Model) { diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 4472662681..e4a7d729ea 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1026,3 +1026,5 @@ "gov.common.votes.format" = "%@ votes"; "gov.common.amount.conviction.format" = "%@ × %@x"; "gov.voters.empty" = "When somebody votes for\nthe referendum they will appear here"; +"gov.referendum.details.dApps.title" = "Use Nova DApp browser"; +"gov.referendum.details.timeline.title" = "Timeline"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 2ba45caed6..296bbce1dc 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1027,3 +1027,5 @@ "gov.common.votes.format" = "%@ голосов"; "gov.common.amount.conviction.format" = "%@ × %@x"; "gov.voters.empty" = "Когда кто-нибудь проголосует\nза референдум они будут отображаться здесь"; +"gov.referendum.details.dApps.title" = "Использовать Nova DApp браузер"; +"gov.referendum.details.timeline.title" = "Статусы" From ca809196a25b215c2256d5aa3e83c0f8fff55466 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 21 Oct 2022 10:21:36 +0500 Subject: [PATCH 075/229] improve locked amount and period calculations --- novawallet.xcodeproj/project.pbxproj | 36 +++++++++++++++++++ .../Model/ReferendumAccountVoteLocal.swift | 14 ++++---- .../Governance/Model/ReferendumNewVote.swift | 12 +++++++ .../Operation/Gov2LockStateFactory.swift | 30 +++++++++++----- .../ReferendumVoteConfirmInteractor.swift | 7 ++++ .../ReferendumVoteConfirmPresenter.swift | 21 +++++++++++ .../ReferendumVoteConfirmProtocols.swift | 11 ++++++ .../ReferendumVoteConfirmViewController.swift | 29 +++++++++++++++ .../ReferendumVoteConfirmViewFactory.swift | 17 +++++++++ .../ReferendumVoteConfirmViewLayout.swift | 12 +++++++ .../ReferendumVoteConfirmWireframe.swift | 3 ++ 11 files changed, 176 insertions(+), 16 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 35b0a5e56c..d7e9dc3305 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ 148748ACAE23B7D15144015B /* DAppAuthSettingsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23EDFB699CAEEADC9263A0D /* DAppAuthSettingsViewFactory.swift */; }; 1550A6E8789263C0D734091A /* StakingUnbondSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC5083A5751A1A3CC95F4F6F /* StakingUnbondSetupWireframe.swift */; }; 1633E4E12AF8B5C16F141944 /* DAppAuthSettingsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 812BCD9B7B25BCA02E32452E /* DAppAuthSettingsInteractor.swift */; }; + 163709FEE6203813261DD771 /* ReferendumVoteConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3531B386DEF40108C34E7232 /* ReferendumVoteConfirmViewLayout.swift */; }; 16FAE3C58B34D700D8A7A217 /* DAppListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E6E41F045986002E1E26C12 /* DAppListWireframe.swift */; }; 1710F415F6AC7BBC622F4BD2 /* ParaStkSelectCollatorsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC320A5EC0D18B6F443BB2E /* ParaStkSelectCollatorsInteractor.swift */; }; 1795E946F1E386442E96E2BC /* StakingPayoutConfirmationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C0AC11A4A195BB697578CE /* StakingPayoutConfirmationPresenter.swift */; }; @@ -184,6 +185,7 @@ 433A3C2B0D1E4BA5974D681B /* DAppAddFavoriteWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ACF32611D345B87BCE29FE0 /* DAppAddFavoriteWireframe.swift */; }; 4387FBFF6D4EFF2E6F3A1A5A /* ParaStkYieldBoostStartViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE30B597680295FFB1B7220C /* ParaStkYieldBoostStartViewFactory.swift */; }; 43DB2CC9864CC7F5904A2DBC /* AdvancedWalletViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B243F6751E2277D9FC14481 /* AdvancedWalletViewFactory.swift */; }; + 441FFD82C502D7300B79EE66 /* ReferendumVoteConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE767858B6CF5F6F7C7B418E /* ReferendumVoteConfirmProtocols.swift */; }; 4448B591D4A193DBC9E2E3BF /* AccountCreateInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7B39A61DB0D2F0F1B1DBA1 /* AccountCreateInteractor.swift */; }; 4453EA83AD59FFD0EF894D58 /* LedgerNetworkSelectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2915C2DF1B65C5CA6009AC28 /* LedgerNetworkSelectionViewLayout.swift */; }; 44D9F74D7851B874F2045E7E /* LedgerInstructionsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E9691A7628B66958F8744 /* LedgerInstructionsProtocols.swift */; }; @@ -281,6 +283,7 @@ 6FDC1CD23BEAF8D4FAF9982D /* NftDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C4C48E50DC14085258AB6D /* NftDetailsViewController.swift */; }; 7050A26051FE62DB06B695F1 /* ParaStkStakeSetupInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28AD18C155A1278B9B53CFDB /* ParaStkStakeSetupInteractor.swift */; }; 70C0E48EE41B4C7229F5946C /* DAppBrowserViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5278A5F4178922A240590334 /* DAppBrowserViewLayout.swift */; }; + 71533ED31DD45841CA8296A3 /* ReferendumVoteConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD1CAB4467C76E4139ECB1B7 /* ReferendumVoteConfirmViewFactory.swift */; }; 716F0819BAB14322E34E416C /* CrowdloanYourContributionsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF4ED0EE2A3EF620DC51870B /* CrowdloanYourContributionsPresenter.swift */; }; 72EA1D180E99C6C78B87B820 /* LedgerInstructionsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6747B9F68F9E92845122D8D2 /* LedgerInstructionsViewLayout.swift */; }; 72EF67BA5380D1CDBB73E23F /* ParaStkYieldBoostStartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6475F9C6C6B095B9C5026CE9 /* ParaStkYieldBoostStartViewController.swift */; }; @@ -2505,6 +2508,7 @@ B1BB78684B059A113AB3AD30 /* DAppPhishingViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36AE1C39767C4CBE3229089D /* DAppPhishingViewFactory.swift */; }; B1CCC5B7BF30F6ACA309B112 /* StakingRedeemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7F5F9B54BE4234C5682BDE /* StakingRedeemViewController.swift */; }; B1F86CA723BB4D69C5EF989D /* ParaStkStakeSetupProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D8246CDA02F544AF9DA2B11 /* ParaStkStakeSetupProtocols.swift */; }; + B30FEC6F62918BC6F38396A2 /* ReferendumVoteConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E2C32A42B0084AFF2911F6E /* ReferendumVoteConfirmViewController.swift */; }; B310C3D126C304851A40CFA9 /* ChainAddressDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E1485C7B322E477D445C84 /* ChainAddressDetailsProtocols.swift */; }; B316F0D2BDF0F44AD27F58E0 /* MoonbeamTermsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4F2B1A2A919663ABEE3367A /* MoonbeamTermsWireframe.swift */; }; B317AB093D99677D292121C4 /* YourWalletsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ED3A7899C88876AB3DCA5F /* YourWalletsViewController.swift */; }; @@ -2603,6 +2607,7 @@ DCE9FE8A75C2FE7B5CB92CC2 /* LedgerWalletConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8167536168325942DA6892E1 /* LedgerWalletConfirmWireframe.swift */; }; DD090C2ED91726FF7779F6C7 /* WalletHistoryFilterViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB10C8DA56E92C280D66BE8 /* WalletHistoryFilterViewFactory.swift */; }; DE03CA5AD7F1D0B80DFF13B6 /* DAppBrowserViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1855972C88E512AED37FD312 /* DAppBrowserViewController.swift */; }; + DE52F23521D54A07F558EB1B /* ReferendumVoteConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1A35F4D82F97C9663F1CD4 /* ReferendumVoteConfirmInteractor.swift */; }; DECE047E7BBE2B9251A09353 /* ParaStkUnstakeConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6060CE86A7EA49AD05329C /* ParaStkUnstakeConfirmViewController.swift */; }; DEF53463C2C780D702E9C2CA /* ParaStkSelectCollatorsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36AB8804B896E72AC81879C6 /* ParaStkSelectCollatorsPresenter.swift */; }; E04E3ABA985AA3D89AE20BF5 /* CrowdloanYourContributionsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 042E8DD6E5F5FD65361A7BDD /* CrowdloanYourContributionsProtocols.swift */; }; @@ -2651,12 +2656,14 @@ EFF8F905CE4E8A212FE79EE4 /* ParaStkYourCollatorsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5E099C1E3DC3730DD503BE /* ParaStkYourCollatorsViewController.swift */; }; F022F1444E0F75CCA42F4648 /* YourValidatorListProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = A31780E84948D7FE632ECB02 /* YourValidatorListProtocols.swift */; }; F0675F495766D07473B065F7 /* CrowdloanYourContributionsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3251EE6FFC95D656BA2146F4 /* CrowdloanYourContributionsInteractor.swift */; }; + F0ADB63765A8EAA19D85C30B /* ReferendumVoteConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB47990BC7A594E663DAC00 /* ReferendumVoteConfirmPresenter.swift */; }; F0B74A766BF50518323AB25C /* DAppAuthConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A9D9D13EC9D921A2C8FB6D /* DAppAuthConfirmWireframe.swift */; }; F0C3DB0CEE1975626B0014A8 /* StakingUnbondConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C34D496D0F57E685237B3A7 /* StakingUnbondConfirmInteractor.swift */; }; F17C7FA0DB540A803558D1BB /* AnalyticsRewardDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85211D55E2AF0A697FB3EB84 /* AnalyticsRewardDetailsPresenter.swift */; }; F1BED07F67119E1BD052952A /* ReferendumVoteSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B2C456A80FA66E6F140814 /* ReferendumVoteSetupWireframe.swift */; }; F20C8D17ABF18B7104E14394 /* StakingAmountInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 312DE7ADA5ABC3214AD3D4AD /* StakingAmountInteractor.swift */; }; F27AAD7BC84793FA63027F8C /* AssetsManageInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA134C6DB56DE1DFBA1B88B4 /* AssetsManageInteractor.swift */; }; + F35B520D7955A70588AB593C /* ReferendumVoteConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C784EDFB9227884E30FBE6E /* ReferendumVoteConfirmWireframe.swift */; }; F382BF4F8C3C46C7C21DE5C0 /* ParaStkUnstakeConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86DCB6F3977BDE1BDC7BC3F9 /* ParaStkUnstakeConfirmPresenter.swift */; }; F3BB50CCA38C9B47FDBEDF53 /* ReferendumVotersInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23CC3812E4DFC26484324D57 /* ReferendumVotersInteractor.swift */; }; F3D2AC37709EAF088A594B73 /* AccountManagementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FCA2DD3A8898D64CBC9F97 /* AccountManagementViewController.swift */; }; @@ -3004,6 +3011,7 @@ 335E8C17DCB794733476AAE3 /* ParaStkStakeConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkStakeConfirmViewController.swift; sourceTree = ""; }; 336395FFC4B2104A9651A2DE /* StakingRewardPayoutsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardPayoutsViewFactory.swift; sourceTree = ""; }; 33DFAA0EEEA7F99C6D1CF4B1 /* ReferendumFullDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsPresenter.swift; sourceTree = ""; }; + 3531B386DEF40108C34E7232 /* ReferendumVoteConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmViewLayout.swift; sourceTree = ""; }; 3558BD7D1B8CA1409BE74879 /* AccountManagementInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountManagementInteractor.swift; sourceTree = ""; }; 3574BADE9CF77599048C7010 /* CrowdloanContributionSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupWireframe.swift; sourceTree = ""; }; 35A4A258D911C67F875E386D /* ParaStkCollatorFiltersViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorFiltersViewController.swift; sourceTree = ""; }; @@ -3030,6 +3038,7 @@ 3BEEFB03BBA45F5143484398 /* ParaStkRedeemViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemViewFactory.swift; sourceTree = ""; }; 3C50BB281AD6DB3CF1493958 /* DAppOperationConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmPresenter.swift; sourceTree = ""; }; 3C535E8504943299B3E4A8EB /* ReferendumFullDetailsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsViewController.swift; sourceTree = ""; }; + 3C784EDFB9227884E30FBE6E /* ReferendumVoteConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmWireframe.swift; sourceTree = ""; }; 3D2A26EC9537BD4275A03272 /* OperationDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OperationDetailsPresenter.swift; sourceTree = ""; }; 3D383344BEDAEDC76A6BE2CE /* DAppTxDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsProtocols.swift; sourceTree = ""; }; 3E6E41F045986002E1E26C12 /* DAppListWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppListWireframe.swift; sourceTree = ""; }; @@ -3063,6 +3072,7 @@ 4C602661DE4D6CAC482AF721 /* ParaStkCollatorsSearchViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorsSearchViewFactory.swift; sourceTree = ""; }; 4C71DEF78B69F017DF460AB7 /* CrowdloanContributionSetupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupViewController.swift; sourceTree = ""; }; 4D8246CDA02F544AF9DA2B11 /* ParaStkStakeSetupProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkStakeSetupProtocols.swift; sourceTree = ""; }; + 4E2C32A42B0084AFF2911F6E /* ReferendumVoteConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmViewController.swift; sourceTree = ""; }; 4E2CF76ABE7BC9A99724D393 /* ParitySignerAddConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddConfirmViewFactory.swift; sourceTree = ""; }; 4E3749525FED4CA4CD0DCDF5 /* CreateWatchOnlyPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CreateWatchOnlyPresenter.swift; sourceTree = ""; }; 4F21FBC9BE578A300A77E9C5 /* ParaStkRebondViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRebondViewLayout.swift; sourceTree = ""; }; @@ -5269,6 +5279,7 @@ AC404A4071AF571FAC4C1994 /* AccountExportPasswordProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountExportPasswordProtocols.swift; sourceTree = ""; }; ACAEDA02F409FE23749A1551 /* AccountCreateWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountCreateWireframe.swift; sourceTree = ""; }; AD0186D779597EAA44B8B188 /* LedgerWalletAccountConfirmationInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerWalletAccountConfirmationInteractor.swift; sourceTree = ""; }; + AD1CAB4467C76E4139ECB1B7 /* ReferendumVoteConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmViewFactory.swift; sourceTree = ""; }; ADD348E749EC6A7E3BB069DE /* StakingUnbondConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondConfirmProtocols.swift; sourceTree = ""; }; AE1000F126679886004753B7 /* ChangeTargetsRecommendationWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeTargetsRecommendationWireframe.swift; sourceTree = ""; }; AE1000F326679946004753B7 /* InitiatedBondingRecommendationWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitiatedBondingRecommendationWireframe.swift; sourceTree = ""; }; @@ -5445,6 +5456,7 @@ CCBCB7C3ABB6C06CD4681D44 /* LedgerTxConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerTxConfirmViewFactory.swift; sourceTree = ""; }; CD098B40697FD6CC08F9A6AC /* UsernameSetupProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UsernameSetupProtocols.swift; sourceTree = ""; }; CD6B5B187E83839481846C7E /* NftDetailsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftDetailsInteractor.swift; sourceTree = ""; }; + CDB47990BC7A594E663DAC00 /* ReferendumVoteConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmPresenter.swift; sourceTree = ""; }; CE294DDEAB7902D7CE1F1BA1 /* AnalyticsRewardDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsRewardDetailsProtocols.swift; sourceTree = ""; }; CE98454DC77EAA01301B9BBF /* ParaStkCollatorFiltersProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorFiltersProtocols.swift; sourceTree = ""; }; CF7A019F89C6CD418AEEE79C /* YourWalletsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourWalletsPresenter.swift; sourceTree = ""; }; @@ -5488,8 +5500,10 @@ DBF9C192200F9B998724FC6C /* DAppSearchViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppSearchViewFactory.swift; sourceTree = ""; }; DBFC5052A062548D20D232DA /* AssetsManageWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetsManageWireframe.swift; sourceTree = ""; }; DD1A2F7E5E278FDCC89FE097 /* OnChainTransferSetupPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OnChainTransferSetupPresenter.swift; sourceTree = ""; }; + DD1A35F4D82F97C9663F1CD4 /* ReferendumVoteConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmInteractor.swift; sourceTree = ""; }; DD2F1EEBF48485F02BF690A4 /* ParaStkStakeSetupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkStakeSetupViewController.swift; sourceTree = ""; }; DDF3C1CFECE4340E82837FC4 /* ReferendumVotersViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVotersViewFactory.swift; sourceTree = ""; }; + DE767858B6CF5F6F7C7B418E /* ReferendumVoteConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmProtocols.swift; sourceTree = ""; }; DF715CEF29477B59119520F1 /* ParitySignerAddressesInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddressesInteractor.swift; sourceTree = ""; }; DFF58EC3A44E4DDDFB4B5C84 /* ParaStkYieldBoostStopViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStopViewLayout.swift; sourceTree = ""; }; E0DB5EA5195D9433A4B90793 /* AdvancedWalletWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AdvancedWalletWireframe.swift; sourceTree = ""; }; @@ -8549,6 +8563,7 @@ 357F2FABE25DB08B50B329CF /* ReferendumVoters */, 8425D0E128FE75EA003B782A /* ReferendumVote */, CEE6BB9D4D5A0E46E857EED4 /* ReferendumVoteSetup */, + B320B465EE16F566DDFE5D8C /* ReferendumVoteConfirm */, ); path = Governance; sourceTree = ""; @@ -12817,6 +12832,20 @@ path = View; sourceTree = ""; }; + B320B465EE16F566DDFE5D8C /* ReferendumVoteConfirm */ = { + isa = PBXGroup; + children = ( + DE767858B6CF5F6F7C7B418E /* ReferendumVoteConfirmProtocols.swift */, + 3C784EDFB9227884E30FBE6E /* ReferendumVoteConfirmWireframe.swift */, + CDB47990BC7A594E663DAC00 /* ReferendumVoteConfirmPresenter.swift */, + DD1A35F4D82F97C9663F1CD4 /* ReferendumVoteConfirmInteractor.swift */, + 4E2C32A42B0084AFF2911F6E /* ReferendumVoteConfirmViewController.swift */, + 3531B386DEF40108C34E7232 /* ReferendumVoteConfirmViewLayout.swift */, + AD1CAB4467C76E4139ECB1B7 /* ReferendumVoteConfirmViewFactory.swift */, + ); + path = ReferendumVoteConfirm; + sourceTree = ""; + }; B492B5426CD384887F1B351D /* DAppSearch */ = { isa = PBXGroup; children = ( @@ -16765,6 +16794,13 @@ 2CEFF4C2574F0AABE0E9BF89 /* ReferendumVoteSetupViewController.swift in Sources */, D1C4208A89633395AF2FDB74 /* ReferendumVoteSetupViewLayout.swift in Sources */, 811096BAAA6BD237DF2769EA /* ReferendumVoteSetupViewFactory.swift in Sources */, + 441FFD82C502D7300B79EE66 /* ReferendumVoteConfirmProtocols.swift in Sources */, + F35B520D7955A70588AB593C /* ReferendumVoteConfirmWireframe.swift in Sources */, + F0ADB63765A8EAA19D85C30B /* ReferendumVoteConfirmPresenter.swift in Sources */, + DE52F23521D54A07F558EB1B /* ReferendumVoteConfirmInteractor.swift in Sources */, + B30FEC6F62918BC6F38396A2 /* ReferendumVoteConfirmViewController.swift in Sources */, + 163709FEE6203813261DD771 /* ReferendumVoteConfirmViewLayout.swift in Sources */, + 71533ED31DD45841CA8296A3 /* ReferendumVoteConfirmViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift index df1783c142..d84b28819a 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift @@ -8,8 +8,8 @@ enum ReferendumAccountVoteLocal { /// post conviction votes for referendum var ayes: BigUInt { switch self { - case let .split(value): - return value.aye + case .split: + return 0 case let .standard(value): if value.vote.aye { return value.vote.conviction.votes(for: value.balance) ?? 0 @@ -21,8 +21,8 @@ enum ReferendumAccountVoteLocal { var nays: BigUInt { switch self { - case let .split(value): - return value.nay + case .split: + return 0 case let .standard(value): if !value.vote.aye { return value.vote.conviction.votes(for: value.balance) ?? 0 @@ -65,16 +65,16 @@ enum ReferendumAccountVoteLocal { var conviction: Decimal? { switch self { case .split: - return 1 + return 0 case let .standard(value): return value.vote.conviction.decimalValue } } - var convictionValue: ConvictionVoting.Conviction { + var convictionValue: ConvictionVoting.Conviction? { switch self { case .split: - return .locked1x + return nil case let .standard(voting): return voting.vote.conviction } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumNewVote.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumNewVote.swift index 913685fddf..2482be105d 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumNewVote.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumNewVote.swift @@ -3,4 +3,16 @@ import Foundation struct ReferendumNewVote { let index: ReferendumIdLocal let voteAction: ReferendumVoteAction + + func toAccountVote() -> ReferendumAccountVoteLocal { + .standard( + .init( + vote: .init( + aye: voteAction.isAye, + conviction: voteAction.conviction + ), + balance: voteAction.amount + ) + ) + } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift index c50be10c0c..4f466110c2 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift @@ -1,6 +1,7 @@ import Foundation import RobinHood import SubstrateSdk +import BigInt final class Gov2LockStateFactory { struct AdditionalInfo { @@ -103,9 +104,11 @@ final class Gov2LockStateFactory { private func calculateLocking( for referendumInfo: ReferendumInfo, - conviction: ConvictionVoting.Conviction, + accountVote: ReferendumAccountVoteLocal, additionalInfo: AdditionalInfo ) -> BlockNumber? { + let conviction = accountVote.convictionValue ?? .none + guard let convictionPeriod = conviction.conviction(for: additionalInfo.voteLockingPeriod) else { return nil } @@ -123,8 +126,18 @@ final class Gov2LockStateFactory { track.decisionPeriod + convictionPeriod } case let .approved(completedStatus): - return completedStatus.since + convictionPeriod - case .unknown, .killed, .timedOut, .cancelled, .rejected: + if accountVote.ayes > 0 { + return completedStatus.since + convictionPeriod + } else { + return nil + } + case let .rejected(completedStatus): + if accountVote.nays > 0 { + return completedStatus.since + convictionPeriod + } else { + return nil + } + case .unknown, .killed, .timedOut, .cancelled: return nil } } @@ -149,8 +162,7 @@ final class Gov2LockStateFactory { return nil } - let conviction = vote.convictionValue - return self.calculateLocking(for: referendum, conviction: conviction, additionalInfo: additions) + return self.calculateLocking(for: referendum, accountVote: vote, additionalInfo: additions) }.max() let oldState = GovernanceLockState(maxLockedAmount: oldAmount, lockedUntil: oldPeriod) @@ -165,23 +177,23 @@ final class Gov2LockStateFactory { let referendumIndex = referendumKeyValue.key let referendum = referendumKeyValue.value - let conviction: ConvictionVoting.Conviction + let accountVote: ReferendumAccountVoteLocal if referendumIndex == newVote.index { guard newVote.voteAction.amount > 0 else { return nil } - conviction = newVote.voteAction.conviction + accountVote = newVote.toAccountVote() } else { guard let vote = filteredVotes[referendumIndex], vote.totalBalance > 0 else { return nil } - conviction = vote.convictionValue + accountVote = vote } - return self.calculateLocking(for: referendum, conviction: conviction, additionalInfo: additions) + return self.calculateLocking(for: referendum, accountVote: accountVote, additionalInfo: additions) }.max() newState = GovernanceLockState(maxLockedAmount: newAmount, lockedUntil: newPeriod) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift new file mode 100644 index 0000000000..8bdf034e1a --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift @@ -0,0 +1,7 @@ +import UIKit + +final class ReferendumVoteConfirmInteractor { + weak var presenter: ReferendumVoteConfirmInteractorOutputProtocol! +} + +extension ReferendumVoteConfirmInteractor: ReferendumVoteConfirmInteractorInputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift new file mode 100644 index 0000000000..16bcbd316b --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift @@ -0,0 +1,21 @@ +import Foundation + +final class ReferendumVoteConfirmPresenter { + weak var view: ReferendumVoteConfirmViewProtocol? + let wireframe: ReferendumVoteConfirmWireframeProtocol + let interactor: ReferendumVoteConfirmInteractorInputProtocol + + init( + interactor: ReferendumVoteConfirmInteractorInputProtocol, + wireframe: ReferendumVoteConfirmWireframeProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + } +} + +extension ReferendumVoteConfirmPresenter: ReferendumVoteConfirmPresenterProtocol { + func setup() {} +} + +extension ReferendumVoteConfirmPresenter: ReferendumVoteConfirmInteractorOutputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift new file mode 100644 index 0000000000..d27f5dc221 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift @@ -0,0 +1,11 @@ +protocol ReferendumVoteConfirmViewProtocol: AnyObject {} + +protocol ReferendumVoteConfirmPresenterProtocol: AnyObject { + func setup() +} + +protocol ReferendumVoteConfirmInteractorInputProtocol: AnyObject {} + +protocol ReferendumVoteConfirmInteractorOutputProtocol: AnyObject {} + +protocol ReferendumVoteConfirmWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift new file mode 100644 index 0000000000..17442e0bd4 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift @@ -0,0 +1,29 @@ +import UIKit + +final class ReferendumVoteConfirmViewController: UIViewController { + typealias RootViewType = ReferendumVoteConfirmViewLayout + + let presenter: ReferendumVoteConfirmPresenterProtocol + + init(presenter: ReferendumVoteConfirmPresenterProtocol) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = ReferendumVoteConfirmViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + presenter.setup() + } +} + +extension ReferendumVoteConfirmViewController: ReferendumVoteConfirmViewProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift new file mode 100644 index 0000000000..13b867df32 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -0,0 +1,17 @@ +import Foundation + +struct ReferendumVoteConfirmViewFactory { + static func createView() -> ReferendumVoteConfirmViewProtocol? { + let interactor = ReferendumVoteConfirmInteractor() + let wireframe = ReferendumVoteConfirmWireframe() + + let presenter = ReferendumVoteConfirmPresenter(interactor: interactor, wireframe: wireframe) + + let view = ReferendumVoteConfirmViewController(presenter: presenter) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift new file mode 100644 index 0000000000..42eb0a0685 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift @@ -0,0 +1,12 @@ +import UIKit + +final class ReferendumVoteConfirmViewLayout: UIView { + override init(frame: CGRect) { + super.init(frame: frame) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift new file mode 100644 index 0000000000..ac03e31278 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class ReferendumVoteConfirmWireframe: ReferendumVoteConfirmWireframeProtocol {} From 9c1457f91f7ad99f80571196733706ade9bbb5e6 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 21 Oct 2022 08:23:56 +0300 Subject: [PATCH 076/229] localizable file fix --- novawallet/ru.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 296bbce1dc..fea5f6cd44 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1028,4 +1028,4 @@ "gov.common.amount.conviction.format" = "%@ × %@x"; "gov.voters.empty" = "Когда кто-нибудь проголосует\nза референдум они будут отображаться здесь"; "gov.referendum.details.dApps.title" = "Использовать Nova DApp браузер"; -"gov.referendum.details.timeline.title" = "Статусы" +"gov.referendum.details.timeline.title" = "Статусы"; From c2dfa91f0d92252091da289938bab296c90837fe Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 21 Oct 2022 10:50:18 +0500 Subject: [PATCH 077/229] refactor base interactor --- .../ReferendumVoteInteractor.swift | 160 +++++++++++++- .../ReferendumVoteInteractorError.swift | 4 + .../ReferendumVoteProtocols.swift | 12 ++ .../ReferendumVoteSetupInteractor.swift | 198 +----------------- .../ReferendumVoteSetupPresenter.swift | 29 +-- .../ReferendumVoteSetupProtocols.swift | 20 +- 6 files changed, 181 insertions(+), 242 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift index 67d60ebc47..28ad88d677 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift @@ -1,8 +1,9 @@ import Foundation import RobinHood import BigInt +import SubstrateSdk -class ReferendumVoteInteractor { +class ReferendumVoteInteractor: AnyCancellableCleaning { weak var basePresenter: ReferendumVoteInteractorOutputProtocol? let referendumIndex: ReferendumIdLocal @@ -14,43 +15,128 @@ class ReferendumVoteInteractor { let extrinsicService: ExtrinsicServiceProtocol let feeProxy: ExtrinsicFeeProxyProtocol let extrinsicFactory: GovernanceExtrinsicFactoryProtocol + let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol + let blockTimeService: BlockTimeEstimationServiceProtocol + let lockStateFactory: GovernanceLockStateFactoryProtocol + let connection: JSONRPCEngine + let runtimeProvider: RuntimeProviderProtocol + let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? private var assetBalanceProvider: StreamableProvider? + private var blockNumberProvider: AnyDataProvider? + + private var blockTimeCancellable: CancellableCall? + private var lockDiffCancellable: CancellableCall? init( referendumIndex: ReferendumIdLocal, selectedAccount: MetaChainAccountResponse, chain: ChainModel, + generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + blockTimeService: BlockTimeEstimationServiceProtocol, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + currencyManager: CurrencyManagerProtocol, extrinsicFactory: GovernanceExtrinsicFactoryProtocol, extrinsicService: ExtrinsicServiceProtocol, feeProxy: ExtrinsicFeeProxyProtocol, - currencyManager: CurrencyManagerProtocol + lockStateFactory: GovernanceLockStateFactoryProtocol, + operationQueue: OperationQueue ) { self.referendumIndex = referendumIndex self.selectedAccount = selectedAccount self.chain = chain + self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory + self.blockTimeService = blockTimeService + self.connection = connection + self.runtimeProvider = runtimeProvider self.referendumsSubscriptionFactory = referendumsSubscriptionFactory self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory self.extrinsicFactory = extrinsicFactory self.extrinsicService = extrinsicService self.feeProxy = feeProxy + self.lockStateFactory = lockStateFactory + self.operationQueue = operationQueue self.currencyManager = currencyManager } deinit { clearReferendumSubscriptions() + clearCancellable() + } + + private func clearCancellable() { + clear(cancellable: &blockTimeCancellable) + clear(cancellable: &lockDiffCancellable) } private func clearReferendumSubscriptions() { referendumsSubscriptionFactory.unsubscribeFromReferendum(self, referendumIndex: referendumIndex) + + referendumsSubscriptionFactory.unsubscribeFromAccountVotes( + self, + accountId: selectedAccount.chainAccount.accountId + ) + } + + private func provideBlockTime() { + guard blockTimeCancellable == nil else { + return + } + + let operation = blockTimeService.createEstimatedBlockTimeOperation() + + operation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard operation === self?.blockTimeCancellable else { + return + } + + self?.blockTimeCancellable = nil + + do { + let blockTimeModel = try operation.extractNoCancellableResultData() + self?.basePresenter?.didReceiveBlockTime(blockTimeModel.blockTime) + } catch { + self?.basePresenter?.didReceiveBaseError(.blockTimeFailed(error)) + } + } + } + + blockTimeCancellable = operation + + operationQueue.addOperation(operation) + } + + private func subscribeAccountVotes() { + referendumsSubscriptionFactory.subscribeToAccountVotes( + self, + accountId: selectedAccount.chainAccount.accountId + ) { [weak self] result in + switch result { + case let .success(storageResult): + self?.basePresenter?.didReceiveAccountVotes(storageResult) + case let .failure(error): + self?.basePresenter?.didReceiveBaseError(.accountVotesFailed(error)) + case .none: + self?.basePresenter?.didReceiveAccountVotes(.init(value: nil, blockHash: nil)) + } + } } - private func subscribeBalanceIfNeeded() { + private func clearAndSubscribeBlockNumber() { + blockNumberProvider?.removeObserver(self) + blockNumberProvider = nil + + blockNumberProvider = subscribeToBlockNumber(for: chain.chainId) + } + + private func clearAndSubscribeBalance() { assetBalanceProvider?.removeObserver(self) assetBalanceProvider = nil @@ -63,7 +149,7 @@ class ReferendumVoteInteractor { } } - private func subscribePriceIfNeeded() { + private func clearAndSubscribePrice() { priceProvider?.removeObserver(self) priceProvider = nil @@ -73,7 +159,9 @@ class ReferendumVoteInteractor { } private func subscribeReferendum() { - referendumsSubscriptionFactory.subscribeToReferendum(self, referendumIndex: referendumIndex) { [weak self] result in + referendumsSubscriptionFactory.subscribeToReferendum( + self, referendumIndex: referendumIndex + ) { [weak self] result in switch result { case let .success(storageResult): if let referendum = storageResult.value { @@ -88,11 +176,13 @@ class ReferendumVoteInteractor { } private func makeSubscriptions() { - subscribeBalanceIfNeeded() - subscribePriceIfNeeded() + clearAndSubscribeBalance() + clearAndSubscribePrice() + clearAndSubscribeBlockNumber() clearReferendumSubscriptions() subscribeReferendum() + subscribeAccountVotes() } func setup() { @@ -122,6 +212,47 @@ extension ReferendumVoteInteractor: ReferendumVoteInteractorInputProtocol { ) } } + + func refreshLockDiff( + for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + newVote: ReferendumNewVote?, + blockHash: Data? + ) { + clear(cancellable: &lockDiffCancellable) + + let wrapper = lockStateFactory.calculateLockStateDiff( + for: votes, + newVote: newVote, + from: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.lockDiffCancellable else { + return + } + + self?.lockDiffCancellable = nil + + do { + let stateDiff = try wrapper.targetOperation.extractNoCancellableResultData() + self?.basePresenter?.didReceiveLockStateDiff(stateDiff) + } catch { + self?.basePresenter?.didReceiveBaseError(.stateDiffFailed(error)) + } + } + } + + lockDiffCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } + + func refreshBlockTime() { + provideBlockTime() + } } extension ReferendumVoteInteractor: WalletLocalSubscriptionHandler, WalletLocalStorageSubscriber { @@ -164,12 +295,25 @@ extension ReferendumVoteInteractor: ExtrinsicFeeProxyDelegate { } } +extension ReferendumVoteInteractor: GeneralLocalStorageSubscriber, GeneralLocalStorageHandler { + func handleBlockNumber(result: Result, chainId _: ChainModel.Id) { + switch result { + case let .success(blockNumber): + if let blockNumber = blockNumber { + basePresenter?.didReceiveBlockNumber(blockNumber) + } + case let .failure(error): + basePresenter?.didReceiveBaseError(.blockNumberSubscriptionFailed(error)) + } + } +} + extension ReferendumVoteInteractor: SelectedCurrencyDepending { func applyCurrency() { guard basePresenter != nil else { return } - subscribePriceIfNeeded() + clearAndSubscribePrice() } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractorError.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractorError.swift index bcfbcbdd4e..32c89e1279 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractorError.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractorError.swift @@ -5,4 +5,8 @@ enum ReferendumVoteInteractorError: Error { case priceFailed(_ internalError: Error) case votingReferendumFailed(_ internalError: Error) case feeFailed(_ internalError: Error) + case accountVotesFailed(_ internalError: Error) + case blockNumberSubscriptionFailed(_ internalError: Error) + case blockTimeFailed(_ internalError: Error) + case stateDiffFailed(_ internalError: Error) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift index 4c0dc61d11..a21e7d870c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift @@ -5,6 +5,12 @@ protocol ReferendumVoteInteractorInputProtocol: AnyObject { func setup() func remakeSubscriptions() func estimateFee(for vote: ReferendumVoteAction) + func refreshLockDiff( + for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + newVote: ReferendumNewVote?, + blockHash: Data? + ) + func refreshBlockTime() } protocol ReferendumVoteInteractorOutputProtocol: AnyObject { @@ -12,5 +18,11 @@ protocol ReferendumVoteInteractorOutputProtocol: AnyObject { func didReceivePrice(_ price: PriceData?) func didReceiveVotingReferendum(_ referendum: ReferendumLocal) func didReceiveFee(_ fee: BigUInt) + func didReceiveLockStateDiff(_ stateDiff: GovernanceLockStateDiff) + func didReceiveAccountVotes( + _ votes: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]> + ) + func didReceiveBlockNumber(_ number: BlockNumber) + func didReceiveBlockTime(_ blockTime: BlockTime) func didReceiveBaseError(_ error: ReferendumVoteInteractorError) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift index d886eb1bf2..815395335a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupInteractor.swift @@ -2,7 +2,7 @@ import UIKit import SubstrateSdk import RobinHood -final class ReferendumVoteSetupInteractor: ReferendumVoteInteractor, AnyCancellableCleaning { +final class ReferendumVoteSetupInteractor: ReferendumVoteInteractor { weak var presenter: ReferendumVoteSetupInteractorOutputProtocol? { get { basePresenter as? ReferendumVoteSetupInteractorOutputProtocol @@ -12,200 +12,6 @@ final class ReferendumVoteSetupInteractor: ReferendumVoteInteractor, AnyCancella basePresenter = newValue } } - - let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol - let blockTimeService: BlockTimeEstimationServiceProtocol - let lockStateFactory: GovernanceLockStateFactoryProtocol - let connection: JSONRPCEngine - let runtimeProvider: RuntimeProviderProtocol - let operationQueue: OperationQueue - - private var blockNumberSubscription: AnyDataProvider? - - private var blockTimeCancellable: CancellableCall? - private var lockDiffCancellable: CancellableCall? - - init( - referendumIndex: ReferendumIdLocal, - selectedAccount: MetaChainAccountResponse, - chain: ChainModel, - generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, - referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, - walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, - priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, - blockTimeService: BlockTimeEstimationServiceProtocol, - connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol, - currencyManager: CurrencyManagerProtocol, - extrinsicFactory: GovernanceExtrinsicFactoryProtocol, - extrinsicService: ExtrinsicServiceProtocol, - feeProxy: ExtrinsicFeeProxyProtocol, - lockStateFactory: GovernanceLockStateFactoryProtocol, - operationQueue: OperationQueue - ) { - self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory - self.blockTimeService = blockTimeService - self.connection = connection - self.runtimeProvider = runtimeProvider - self.lockStateFactory = lockStateFactory - self.operationQueue = operationQueue - - super.init( - referendumIndex: referendumIndex, - selectedAccount: selectedAccount, - chain: chain, - referendumsSubscriptionFactory: referendumsSubscriptionFactory, - walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, - priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, - extrinsicFactory: extrinsicFactory, - extrinsicService: extrinsicService, - feeProxy: feeProxy, - currencyManager: currencyManager - ) - } - - deinit { - clearReferendumSubscriptions() - clearCancellable() - } - - private func clearCancellable() { - clear(cancellable: &blockTimeCancellable) - clear(cancellable: &lockDiffCancellable) - } - - private func provideBlockTime() { - guard blockTimeCancellable == nil else { - return - } - - let operation = blockTimeService.createEstimatedBlockTimeOperation() - - operation.completionBlock = { [weak self] in - DispatchQueue.main.async { - guard operation === self?.blockTimeCancellable else { - return - } - - self?.blockTimeCancellable = nil - - do { - let blockTimeModel = try operation.extractNoCancellableResultData() - self?.presenter?.didReceiveBlockTime(blockTimeModel.blockTime) - } catch { - self?.presenter?.didReceiveError(.blockTimeFailed(error)) - } - } - } - - blockTimeCancellable = operation - - operationQueue.addOperation(operation) - } - - private func clearReferendumSubscriptions() { - referendumsSubscriptionFactory.unsubscribeFromAccountVotes( - self, - accountId: selectedAccount.chainAccount.accountId - ) - } - - private func clearAndSubscribeBlockNumber() { - blockNumberSubscription?.removeObserver(self) - blockNumberSubscription = nil - - blockNumberSubscription = subscribeToBlockNumber(for: chain.chainId) - } - - private func subscribeAccountVotes() { - clearReferendumSubscriptions() - - referendumsSubscriptionFactory.subscribeToAccountVotes( - self, - accountId: selectedAccount.chainAccount.accountId - ) { [weak self] result in - switch result { - case let .success(storageResult): - self?.presenter?.didReceiveAccountVotes(storageResult) - case let .failure(error): - self?.presenter?.didReceiveError(.accountVotesFailed(error)) - case .none: - self?.presenter?.didReceiveAccountVotes(.init(value: nil, blockHash: nil)) - } - } - } - - private func makeSubscriptions() { - clearAndSubscribeBlockNumber() - - subscribeAccountVotes() - } - - override func setup() { - super.setup() - - makeSubscriptions() - } - - override func remakeSubscriptions() { - super.remakeSubscriptions() - - makeSubscriptions() - } -} - -extension ReferendumVoteSetupInteractor: ReferendumVoteSetupInteractorInputProtocol { - func refreshLockDiff( - for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], - newVote: ReferendumNewVote?, - blockHash: Data? - ) { - clear(cancellable: &lockDiffCancellable) - - let wrapper = lockStateFactory.calculateLockStateDiff( - for: votes, - newVote: newVote, - from: connection, - runtimeProvider: runtimeProvider, - blockHash: blockHash - ) - - wrapper.targetOperation.completionBlock = { [weak self] in - DispatchQueue.main.async { - guard wrapper === self?.lockDiffCancellable else { - return - } - - self?.lockDiffCancellable = nil - - do { - let stateDiff = try wrapper.targetOperation.extractNoCancellableResultData() - self?.presenter?.didReceiveLockStateDiff(stateDiff) - } catch { - self?.presenter?.didReceiveError(.stateDiffFailed(error)) - } - } - } - - lockDiffCancellable = wrapper - - operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) - } - - func refreshBlockTime() { - provideBlockTime() - } } -extension ReferendumVoteSetupInteractor: GeneralLocalStorageSubscriber, GeneralLocalStorageHandler { - func handleBlockNumber(result: Result, chainId _: ChainModel.Id) { - switch result { - case let .success(blockNumber): - if let blockNumber = blockNumber { - presenter?.didReceiveBlockNumber(blockNumber) - } - case let .failure(error): - presenter?.didReceiveError(.blockNumberSubscriptionFailed(error)) - } - } -} +extension ReferendumVoteSetupInteractor: ReferendumVoteSetupInteractorInputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 5c5ed1ff51..3b8da5eb79 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -312,25 +312,6 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto updateLockedPeriodView() } - func didReceiveError(_ error: ReferendumVoteSetupInteractorError) { - logger.error("Did receive setup error: \(error)") - - switch error { - case .accountVotesFailed, .blockNumberSubscriptionFailed: - wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in - self?.interactor.remakeSubscriptions() - } - case .blockTimeFailed: - wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in - self?.interactor.refreshBlockTime() - } - case .stateDiffFailed: - wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in - self?.refreshLockDiff() - } - } - } - func didReceiveAssetBalance(_ assetBalance: AssetBalance?) { self.assetBalance = assetBalance @@ -362,7 +343,7 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto logger.error("Did receive base error: \(error)") switch error { - case .assetBalanceFailed, .priceFailed, .votingReferendumFailed: + case .assetBalanceFailed, .priceFailed, .votingReferendumFailed, .accountVotesFailed, .blockNumberSubscriptionFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in self?.interactor.remakeSubscriptions() } @@ -370,6 +351,14 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto wireframe.presentFeeStatus(on: view, locale: selectedLocale) { [weak self] in self?.refreshFee() } + case .blockTimeFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refreshBlockTime() + } + case .stateDiffFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.refreshLockDiff() + } } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index 2242819c2d..9d77674afd 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -22,24 +22,8 @@ protocol ReferendumVoteSetupPresenterProtocol: AnyObject { func proceedAye() } -protocol ReferendumVoteSetupInteractorInputProtocol: ReferendumVoteInteractorInputProtocol { - func refreshLockDiff( - for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], - newVote: ReferendumNewVote?, - blockHash: Data? - ) +protocol ReferendumVoteSetupInteractorInputProtocol: ReferendumVoteInteractorInputProtocol {} - func refreshBlockTime() -} - -protocol ReferendumVoteSetupInteractorOutputProtocol: ReferendumVoteInteractorOutputProtocol { - func didReceiveLockStateDiff(_ stateDiff: GovernanceLockStateDiff) - func didReceiveAccountVotes( - _ votes: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]> - ) - func didReceiveBlockNumber(_ number: BlockNumber) - func didReceiveBlockTime(_ blockTime: BlockTime) - func didReceiveError(_ error: ReferendumVoteSetupInteractorError) -} +protocol ReferendumVoteSetupInteractorOutputProtocol: ReferendumVoteInteractorOutputProtocol {} protocol ReferendumVoteSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, FeeRetryable {} From b346730003ef21153399f6b8dd8a4cd437347b64 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 21 Oct 2022 14:16:56 +0500 Subject: [PATCH 078/229] refactor account votes --- novawallet.xcodeproj/project.pbxproj | 8 ++++ .../Model/ReferendumAccountVoteLocal.swift | 16 ++++---- .../Model/ReferendumDelegatingLocal.swift | 22 +++++++++++ .../Governance/Model/ReferendumLocal.swift | 1 + .../Model/ReferendumVotingLocal.swift | 37 +++++++++++++++++++ .../Operation/Gov2LockStateFactory.swift | 2 +- .../Operation/Gov2OperationFactory.swift | 26 +++++++++---- .../GovernanceOperationProtocols.swift | 2 +- .../ReferendumDetailsInteractor.swift | 2 +- .../ReferendumVoteProtocols.swift | 2 +- .../ReferendumVoteSetupPresenter.swift | 15 +++++--- .../Referendums/ReferendumsInteractor.swift | 2 +- .../Gov2SubscriptionFactory.swift | 8 ++-- .../GovernanceSubscriptionProtocol.swift | 2 +- 14 files changed, 116 insertions(+), 29 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumDelegatingLocal.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index d7e9dc3305..4ed8348bcf 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1269,6 +1269,8 @@ 8487584B27F1834E00495306 /* ImageGalleryPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8487584A27F1834E00495306 /* ImageGalleryPresentable.swift */; }; 84880C4029016F1500CADB06 /* ReferendumLockChangeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84880C3F29016F1500CADB06 /* ReferendumLockChangeViewModel.swift */; }; 84880C42290172C300CADB06 /* ReferendumLockChangeViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84880C41290172C300CADB06 /* ReferendumLockChangeViewModelFactory.swift */; }; + 84880C4429026C3E00CADB06 /* ReferendumDelegatingLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84880C4329026C3E00CADB06 /* ReferendumDelegatingLocal.swift */; }; + 84880C462902781E00CADB06 /* ReferendumVotingLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84880C452902781E00CADB06 /* ReferendumVotingLocal.swift */; }; 848841C128D1229000D750E9 /* ParaStkYieldBoostStopError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848841C028D1229000D750E9 /* ParaStkYieldBoostStopError.swift */; }; 84884B5F27A1336500FAC549 /* OrmlAssetExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84884B5E27A1336500FAC549 /* OrmlAssetExtras.swift */; }; 8488ECD7258CDCBC004591CC /* PurchaseCompletionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8488ECD6258CDCBC004591CC /* PurchaseCompletionHandler.swift */; }; @@ -4152,6 +4154,8 @@ 8487584A27F1834E00495306 /* ImageGalleryPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGalleryPresentable.swift; sourceTree = ""; }; 84880C3F29016F1500CADB06 /* ReferendumLockChangeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLockChangeViewModel.swift; sourceTree = ""; }; 84880C41290172C300CADB06 /* ReferendumLockChangeViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLockChangeViewModelFactory.swift; sourceTree = ""; }; + 84880C4329026C3E00CADB06 /* ReferendumDelegatingLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDelegatingLocal.swift; sourceTree = ""; }; + 84880C452902781E00CADB06 /* ReferendumVotingLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotingLocal.swift; sourceTree = ""; }; 848841C028D1229000D750E9 /* ParaStkYieldBoostStopError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStopError.swift; sourceTree = ""; }; 84884B5E27A1336500FAC549 /* OrmlAssetExtras.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrmlAssetExtras.swift; sourceTree = ""; }; 8488ECD6258CDCBC004591CC /* PurchaseCompletionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseCompletionHandler.swift; sourceTree = ""; }; @@ -11350,6 +11354,8 @@ 8425D0ED28FE9BF1003B782A /* ReferendumVoteAction.swift */, 8427495028FEB6E500B2B70B /* GovernanceLockState.swift */, 8427495228FEB8C800B2B70B /* ReferendumNewVote.swift */, + 84880C4329026C3E00CADB06 /* ReferendumDelegatingLocal.swift */, + 84880C452902781E00CADB06 /* ReferendumVotingLocal.swift */, ); path = Model; sourceTree = ""; @@ -15648,6 +15654,7 @@ 849A4EF2279A787200AB6709 /* AssetsUpdatingService.swift in Sources */, 84B018AC26E01A4100C75E28 /* StakingStateView.swift in Sources */, 842A737C27DCC489006EE1EA /* OperationDetailsTransferView.swift in Sources */, + 84880C4429026C3E00CADB06 /* ReferendumDelegatingLocal.swift in Sources */, 8472C5B2265CF9C500E2481B /* StakingRewardDestConfirmInteractor.swift in Sources */, 882C29AE28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift in Sources */, 846CA77A27099B1E0011124C /* StakingAnalyticsLocalSubscriptionFactory.swift in Sources */, @@ -15841,6 +15848,7 @@ 84EA0B2A25E579DF00AFB0DC /* AssetBalanceViewModel.swift in Sources */, 84FD3DAF2540BEA000A234E3 /* TransactionHistoryItem+Wallet.swift in Sources */, 84452F9825D6728B00F47EC5 /* RuntimeVersionSubscription.swift in Sources */, + 84880C462902781E00CADB06 /* ReferendumVotingLocal.swift in Sources */, 84CEAAF326D6ED870021B881 /* KeystoreTag.swift in Sources */, 840DCBF625E0059D00D45C6A /* AmountInputView+Inspectable.swift in Sources */, 8488ECEA258CE456004591CC /* PurchaseViewController.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift index d84b28819a..dc17b026d2 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift @@ -8,8 +8,9 @@ enum ReferendumAccountVoteLocal { /// post conviction votes for referendum var ayes: BigUInt { switch self { - case .split: - return 0 + case let .split(value): + let splitConviction = ConvictionVoting.Conviction.none + return splitConviction.votes(for: value.aye) ?? 0 case let .standard(value): if value.vote.aye { return value.vote.conviction.votes(for: value.balance) ?? 0 @@ -21,8 +22,9 @@ enum ReferendumAccountVoteLocal { var nays: BigUInt { switch self { - case .split: - return 0 + case let .split(value): + let splitConviction = ConvictionVoting.Conviction.none + return splitConviction.votes(for: value.nay) ?? 0 case let .standard(value): if !value.vote.aye { return value.vote.conviction.votes(for: value.balance) ?? 0 @@ -65,16 +67,16 @@ enum ReferendumAccountVoteLocal { var conviction: Decimal? { switch self { case .split: - return 0 + return 0.1 case let .standard(value): return value.vote.conviction.decimalValue } } - var convictionValue: ConvictionVoting.Conviction? { + var convictionValue: ConvictionVoting.Conviction { switch self { case .split: - return nil + return .none case let .standard(voting): return voting.vote.conviction } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumDelegatingLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumDelegatingLocal.swift new file mode 100644 index 0000000000..f40da966e2 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumDelegatingLocal.swift @@ -0,0 +1,22 @@ +import Foundation +import BigInt + +struct ReferendumDelegatingLocal { + let balance: BigUInt + + let target: AccountId + + let conviction: ConvictionVoting.Conviction + + let delegations: ConvictionVoting.Delegations + + let prior: ConvictionVoting.PriorLock + + init(remote: ConvictionVoting.Delegating) { + balance = remote.balance + target = remote.target + conviction = remote.conviction + delegations = remote.delegations + prior = remote.prior + } +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 11ab4371d0..c693cf42ff 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -3,6 +3,7 @@ import BigInt import SubstrateSdk typealias ReferendumIdLocal = UInt +typealias TrackIdLocal = UInt struct ReferendumLocal { let index: ReferendumIdLocal diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift new file mode 100644 index 0000000000..4f409b3f42 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift @@ -0,0 +1,37 @@ +import Foundation + +struct ReferendumAccountVotingDistribution { + let votes: [ReferendumIdLocal: ReferendumAccountVoteLocal] + let delegatings: [TrackIdLocal: ReferendumDelegatingLocal] + + func addingVote( + _ vote: ReferendumAccountVoteLocal, + referendumId: ReferendumIdLocal + ) -> ReferendumAccountVotingDistribution { + var newVotes = votes + newVotes[referendumId] = vote + + return ReferendumAccountVotingDistribution( + votes: newVotes, + delegatings: delegatings + ) + } + + func addingDelegating( + _ delegating: ReferendumDelegatingLocal, + trackId: TrackIdLocal + ) -> ReferendumAccountVotingDistribution { + var newDelegatings = delegatings + newDelegatings[trackId] = delegating + + return ReferendumAccountVotingDistribution( + votes: votes, + delegatings: newDelegatings + ) + } +} + +struct ReferendumTracksVotingDistribution { + let votes: ReferendumAccountVotingDistribution + let trackLocks: [ConvictionVoting.ClassLock] +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift index 4f466110c2..1be05129d1 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift @@ -107,7 +107,7 @@ final class Gov2LockStateFactory { accountVote: ReferendumAccountVoteLocal, additionalInfo: AdditionalInfo ) -> BlockNumber? { - let conviction = accountVote.convictionValue ?? .none + let conviction = accountVote.convictionValue guard let convictionPeriod = conviction.conviction(for: additionalInfo.voteLockingPeriod) else { return nil diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 844106f20c..8368db7723 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -280,7 +280,7 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockHash: Data? - ) -> CompoundOperationWrapper<[UInt: ReferendumAccountVoteLocal]> { + ) -> CompoundOperationWrapper { let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() let request = MapRemoteStorageRequest(storagePath: ConvictionVoting.votingFor) { @@ -298,17 +298,27 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { votesWrapper.addDependency(operations: [codingFactoryOperation]) - let mappingOperation = ClosureOperation<[UInt: ReferendumAccountVoteLocal]> { - let votes = try votesWrapper.targetOperation.extractNoCancellableResultData().values + let mappingOperation = ClosureOperation { + let voting = try votesWrapper.targetOperation.extractNoCancellableResultData() - return votes.reduce(into: [UInt: ReferendumAccountVoteLocal]()) { result, voting in + let initVotingLocal = ReferendumAccountVotingDistribution(votes: [:], delegatings: [:]) + return voting.reduce(initVotingLocal) { resultVoting, votingKeyValue in + let voting = votingKeyValue.value + let track = votingKeyValue.key.trackId switch voting { case let .casting(castingVoting): - castingVoting.votes.forEach { vote in - result[UInt(vote.pollIndex)] = ReferendumAccountVoteLocal(accountVote: vote.accountVote) + return castingVoting.votes.reduce(resultVoting) { result, vote in + guard let localVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { + return result + } + + return result.addingVote(localVote, referendumId: ReferendumIdLocal(vote.pollIndex)) } - case .delegating, .unknown: - break + case let .delegating(delegatingVoting): + let delegatingLocal = ReferendumDelegatingLocal(remote: delegatingVoting) + return resultVoting.addingDelegating(delegatingLocal, trackId: TrackIdLocal(track)) + case .unknown: + return resultVoting } } } diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift index 792420e4bd..d4be0dfe19 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -13,7 +13,7 @@ protocol ReferendumsOperationFactoryProtocol { from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockHash: Data? - ) -> CompoundOperationWrapper<[UInt: ReferendumAccountVoteLocal]> + ) -> CompoundOperationWrapper func fetchVotersWrapper( for referendumIndex: ReferendumIdLocal, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 75ba3c54d1..39f548ed94 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -100,7 +100,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { ) { [weak self] result in switch result { case let .success(votesResult): - if let votes = votesResult.value, let referendumId = self?.referendum.index { + if let votes = votesResult.value?.votes.votes, let referendumId = self?.referendum.index { self?.presenter?.didReceiveAccountVotes(votes[referendumId]) } case let .failure(error): diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift index a21e7d870c..e8f7feb396 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift @@ -20,7 +20,7 @@ protocol ReferendumVoteInteractorOutputProtocol: AnyObject { func didReceiveFee(_ fee: BigUInt) func didReceiveLockStateDiff(_ stateDiff: GovernanceLockStateDiff) func didReceiveAccountVotes( - _ votes: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]> + _ votes: CallbackStorageSubscriptionResult ) func didReceiveBlockNumber(_ number: BlockNumber) func didReceiveBlockTime(_ blockTime: BlockTime) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 3b8da5eb79..27a12b0251 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -20,7 +20,7 @@ final class ReferendumVoteSetupPresenter { private var assetBalance: AssetBalance? private var fee: BigUInt? private var priceData: PriceData? - private var votesResult: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]>? + private var votesResult: CallbackStorageSubscriptionResult? private var blockNumber: BlockNumber? private var blockTime: BlockTime? private var referendum: ReferendumLocal? @@ -229,7 +229,11 @@ final class ReferendumVoteSetupPresenter { return } - interactor.refreshLockDiff(for: votesResult.value ?? [:], newVote: newVote, blockHash: votesResult.blockHash) + interactor.refreshLockDiff( + for: votesResult.value?.votes.votes ?? [:], + newVote: newVote, + blockHash: votesResult.blockHash + ) } } @@ -289,9 +293,9 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto } func didReceiveAccountVotes( - _ votesResult: CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]> + _ votes: CallbackStorageSubscriptionResult ) { - self.votesResult = votesResult + votesResult = votes refreshLockDiff() } @@ -343,7 +347,8 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto logger.error("Did receive base error: \(error)") switch error { - case .assetBalanceFailed, .priceFailed, .votingReferendumFailed, .accountVotesFailed, .blockNumberSubscriptionFailed: + case .assetBalanceFailed, .priceFailed, .votingReferendumFailed, .accountVotesFailed, + .blockNumberSubscriptionFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in self?.interactor.remakeSubscriptions() } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index fecfb2737c..429aa56068 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -299,7 +299,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani self?.votesCancellable = nil do { - let votes = try wrapper.targetOperation.extractNoCancellableResultData() + let votes = try wrapper.targetOperation.extractNoCancellableResultData().votes self?.presenter?.didReceiveVotes(votes) } catch { self?.presenter?.didReceiveError(.votesFetchFailed(error)) diff --git a/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift b/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift index 890e21d38a..8214c8871d 100644 --- a/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift +++ b/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift @@ -117,6 +117,7 @@ final class Gov2SubscriptionFactory: AnyCancellableCleaning { case let .success(result): handleVotes( for: accountId, + trackLocks: result.value ?? [], connection: connection, runtimeProvider: runtimeProvider, blockHash: result.blockHash @@ -128,6 +129,7 @@ final class Gov2SubscriptionFactory: AnyCancellableCleaning { private func handleVotes( for accountId: AccountId, + trackLocks: [ConvictionVoting.ClassLock], connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockHash: Data? @@ -151,9 +153,9 @@ final class Gov2SubscriptionFactory: AnyCancellableCleaning { self?.cancellables[cancellableKey] = nil do { - let votes = try wrapper.targetOperation.extractNoCancellableResultData() - let value = CallbackStorageSubscriptionResult<[UInt: ReferendumAccountVoteLocal]>( - value: votes, + let accountVoting = try wrapper.targetOperation.extractNoCancellableResultData() + let value = CallbackStorageSubscriptionResult( + value: .init(votes: accountVoting, trackLocks: trackLocks), blockHash: blockHash ) diff --git a/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift b/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift index 6abab62439..46139c161e 100644 --- a/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift +++ b/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift @@ -3,7 +3,7 @@ import Foundation typealias ReferendumSubscriptionResult = Result, Error> typealias ReferendumVotesSubscriptionResult = Result< - CallbackStorageSubscriptionResult<[ReferendumIdLocal: ReferendumAccountVoteLocal]>, + CallbackStorageSubscriptionResult, Error > From 47bc18e8496876d6ee13f7f676b82af3d9e5b5a1 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 21 Oct 2022 15:13:09 +0500 Subject: [PATCH 079/229] base interactor --- .../ReferendumVoteConfirmInteractor.swift | 68 ++++++++++++++++++- .../ReferendumVoteConfirmProtocols.swift | 6 +- .../ReferendumVoteConfirmViewFactory.swift | 5 +- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift index 8bdf034e1a..631d74cb2b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift @@ -1,7 +1,69 @@ import UIKit +import SubstrateSdk -final class ReferendumVoteConfirmInteractor { - weak var presenter: ReferendumVoteConfirmInteractorOutputProtocol! +final class ReferendumVoteConfirmInteractor: ReferendumVoteInteractor { + weak var presenter: ReferendumVoteConfirmInteractorOutputProtocol? + + let signer: SigningWrapperProtocol + + init( + referendumIndex: ReferendumIdLocal, + selectedAccount: MetaChainAccountResponse, + chain: ChainModel, + generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, + referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + blockTimeService: BlockTimeEstimationServiceProtocol, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + currencyManager: CurrencyManagerProtocol, + extrinsicFactory: GovernanceExtrinsicFactoryProtocol, + extrinsicService: ExtrinsicServiceProtocol, + signer: SigningWrapperProtocol, + feeProxy: ExtrinsicFeeProxyProtocol, + lockStateFactory: GovernanceLockStateFactoryProtocol, + operationQueue: OperationQueue + ) { + self.signer = signer + + super.init( + referendumIndex: referendumIndex, + selectedAccount: selectedAccount, + chain: chain, + generalLocalSubscriptionFactory: generalLocalSubscriptionFactory, + referendumsSubscriptionFactory: referendumsSubscriptionFactory, + walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, + priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, + blockTimeService: blockTimeService, + connection: connection, + runtimeProvider: runtimeProvider, + currencyManager: currencyManager, + extrinsicFactory: extrinsicFactory, + extrinsicService: extrinsicService, + feeProxy: feeProxy, + lockStateFactory: lockStateFactory, + operationQueue: operationQueue + ) + } } -extension ReferendumVoteConfirmInteractor: ReferendumVoteConfirmInteractorInputProtocol {} +extension ReferendumVoteConfirmInteractor: ReferendumVoteConfirmInteractorInputProtocol { + func submit(vote: ReferendumVoteAction) { + let closure: ExtrinsicBuilderClosure = { [weak self] builder in + guard let strongSelf = self else { + return builder + } + + return try strongSelf.extrinsicFactory.vote( + vote, + referendum: strongSelf.referendumIndex, + builder: builder + ) + } + + extrinsicService.submit(closure, signer: signer, runningIn: .main) { [weak self] result in + + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift index d27f5dc221..4ba9e1bd9e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift @@ -1,10 +1,12 @@ -protocol ReferendumVoteConfirmViewProtocol: AnyObject {} +protocol ReferendumVoteConfirmViewProtocol: ControllerBackedProtocol {} protocol ReferendumVoteConfirmPresenterProtocol: AnyObject { func setup() } -protocol ReferendumVoteConfirmInteractorInputProtocol: AnyObject {} +protocol ReferendumVoteConfirmInteractorInputProtocol: ReferendumVoteInteractorInputProtocol { + func submit(vote: ReferendumVoteAction) +} protocol ReferendumVoteConfirmInteractorOutputProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift index 13b867df32..80547f43dc 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -1,7 +1,10 @@ import Foundation struct ReferendumVoteConfirmViewFactory { - static func createView() -> ReferendumVoteConfirmViewProtocol? { + static func createView( + for state: GovernanceLockState, + newVote: ReferendumNewVote + ) -> ReferendumVoteConfirmViewProtocol? { let interactor = ReferendumVoteConfirmInteractor() let wireframe = ReferendumVoteConfirmWireframe() From 22f9192fd6790eae0c308d31d37320f81a0c3ea8 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 21 Oct 2022 17:04:38 +0500 Subject: [PATCH 080/229] open voting setup from details --- .../ReferendumDetailsPresenter.swift | 4 + .../ReferendumDetailsProtocols.swift | 3 + .../ReferendumDetailsViewController.swift | 14 ++++ .../ReferendumDetailsViewLayout.swift | 2 +- .../ReferendumDetailsWireframe.swift | 14 ++++ .../ReferendumVotingStatusDetailsView.swift | 15 +++- .../ReferendumVoteConfirmInteractor.swift | 3 +- .../ReferendumVoteConfirmViewFactory.swift | 79 ++++++++++++++++++- .../Referendums/ReferendumsWireframe.swift | 4 +- 9 files changed, 128 insertions(+), 10 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 3840b157aa..4c6443055e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -39,6 +39,10 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { func setup() { interactor.setup() } + + func vote() { + wireframe.showVote(from: view, referendum: referendum) + } } extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 06c4e9f1c9..feb5b9f936 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -10,6 +10,7 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { protocol ReferendumDetailsPresenterProtocol: AnyObject { func setup() + func vote() } protocol ReferendumDetailsInteractorInputProtocol: AnyObject { @@ -39,4 +40,6 @@ protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, actionDetails: ReferendumActionLocal, identities: [AccountAddress: AccountIdentity] ) + + func showVote(from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 9433447c39..b15344899e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -23,10 +23,24 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { override func viewDidLoad() { super.viewDidLoad() + setupHandlers() + presenter.setup() setSamples() } + private func setupHandlers() { + rootView.votingDetailsRow.voteButton.addTarget( + self, + action: #selector(actionVote), + for: .touchUpInside + ) + } + + @objc private func actionVote() { + presenter.vote() + } + private func setSamples() { let status = ReferendumVotingStatusView.Model( status: .init(name: "PASSING", kind: .positive), diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 741f5cafe8..4097ea43f2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -10,7 +10,7 @@ final class ReferendumDetailsViewLayout: UIView { }() let titleView = ReferendumDetailsTitleView() - let votingDetailsRow = VotingDetailsRow(frame: .zero) + let votingDetailsRow = ReferendumVotingStatusDetailsView() let dAppsTableView = StackTableView() var timelineTableView = StackTableView() diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index 43d65b9776..2d07fbaab1 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -27,4 +27,18 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { view?.controller.present(navigationController, animated: true) } + + func showVote(from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal) { + guard + let voteSetupView = ReferendumVoteSetupViewFactory.createView( + for: state, + referendum: referendum.index + ) else { + return + } + + let navigationController = ImportantFlowViewFactory.createNavigation(from: voteSetupView.controller) + + view?.controller.present(navigationController, animated: true) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift index 7ffb49f779..d931916a4c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -1,6 +1,7 @@ import UIKit +import SoraUI -final class ReferendumVotingStatusDetailsView: UIView { +final class ReferendumVotingStatusDetailsView: RoundedView { let statusView = ReferendumVotingStatusView() let votingProgressView = VotingProgressView() let ayeVotesView: VoteRowView = .create { @@ -17,13 +18,18 @@ final class ReferendumVotingStatusDetailsView: UIView { )) } - let voteButton: ButtonLargeControl = .create { - $0.titleLabel.textAlignment = .center + let voteButton: TriangularedButton = .create { + $0.applyDefaultStyle() } override init(frame: CGRect) { super.init(frame: frame) + applyFilledBackgroundStyle() + + fillColor = R.color.colorWhite8()! + cornerRadius = 12.0 + setupLayout() } @@ -71,7 +77,8 @@ extension ReferendumVotingStatusDetailsView: BindableView { nayVotesView.bindOrHide(viewModel: viewModel.nay) if let buttonText = viewModel.buttonText { voteButton.isHidden = false - voteButton.bind(title: buttonText, details: nil) + voteButton.imageWithTitleView?.title = buttonText + voteButton.invalidateLayout() } else { voteButton.isHidden = true } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift index 631d74cb2b..2a708937b3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift @@ -62,8 +62,7 @@ extension ReferendumVoteConfirmInteractor: ReferendumVoteConfirmInteractorInputP ) } - extrinsicService.submit(closure, signer: signer, runningIn: .main) { [weak self] result in - + extrinsicService.submit(closure, signer: signer, runningIn: .main) { [weak self] _ in } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift index 80547f43dc..2c90f8cbb2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -1,11 +1,22 @@ import Foundation +import RobinHood +import SubstrateSdk struct ReferendumVoteConfirmViewFactory { static func createView( - for state: GovernanceLockState, + for state: GovernanceSharedState, newVote: ReferendumNewVote ) -> ReferendumVoteConfirmViewProtocol? { - let interactor = ReferendumVoteConfirmInteractor() + guard + let currencyManager = CurrencyManager.shared, + let interactor = createInteractor( + for: state, + referendum: newVote.index, + currencyManager: currencyManager + ) else { + return nil + } + let wireframe = ReferendumVoteConfirmWireframe() let presenter = ReferendumVoteConfirmPresenter(interactor: interactor, wireframe: wireframe) @@ -17,4 +28,68 @@ struct ReferendumVoteConfirmViewFactory { return view } + + private static func createInteractor( + for state: GovernanceSharedState, + referendum: ReferendumIdLocal, + currencyManager: CurrencyManagerProtocol + ) -> ReferendumVoteConfirmInteractor? { + let wallet: MetaAccountModel? = SelectedWalletSettings.shared.value + + guard + let chain = state.settings.value, + let selectedAccount = wallet?.fetchMetaChainAccount(for: chain.accountRequest()), + let subscriptionFactory = state.subscriptionFactory, + let blockTimeService = state.blockTimeService + else { + return nil + } + + guard + let connection = state.chainRegistry.getConnection(for: chain.chainId), + let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId) else { + return nil + } + + let operationQueue = OperationManagerFacade.sharedDefaultQueue + let operationManager = OperationManager(operationQueue: operationQueue) + + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: operationManager + ) + + let lockStateFactory = Gov2LockStateFactory(requestFactory: requestFactory) + + let extrinsicService = ExtrinsicServiceFactory( + runtimeRegistry: runtimeProvider, + engine: connection, + operationManager: operationManager + ).createService(account: selectedAccount.chainAccount, chain: chain) + + let signer = SigningWrapperFactory().createSigningWrapper( + for: selectedAccount.metaId, + accountResponse: selectedAccount.chainAccount + ) + + return ReferendumVoteConfirmInteractor( + referendumIndex: referendum, + selectedAccount: selectedAccount, + chain: chain, + generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, + referendumsSubscriptionFactory: subscriptionFactory, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + blockTimeService: blockTimeService, + connection: connection, + runtimeProvider: runtimeProvider, + currencyManager: currencyManager, + extrinsicFactory: Gov2ExtrinsicFactory(), + extrinsicService: extrinsicService, + signer: signer, + feeProxy: ExtrinsicFeeProxy(), + lockStateFactory: lockStateFactory, + operationQueue: operationQueue + ) + } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index 82fe6f7832..dbaac6d3ee 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -32,10 +32,12 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { } func showReferendumDetails(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) { - guard let detailsView = ReferendumVoteSetupViewFactory.createView(for: state, referendum: referendum.index) else { + guard let detailsView = ReferendumDetailsViewFactory.createView(for: referendum, state: state) else { return } + detailsView.controller.hidesBottomBarWhenPushed = true + view?.controller.navigationController?.pushViewController(detailsView.controller, animated: true) } } From feffb547b847d37b3d5a2ce03dcc329464270995 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 21 Oct 2022 18:45:11 +0500 Subject: [PATCH 081/229] confirmation view layout add --- novawallet.xcodeproj/project.pbxproj | 8 ++ .../Contents.json | 12 +++ .../iconGovTransferable.pdf | Bin 0 -> 3259 bytes .../Common/View/StackTitleValueDiffCell.swift | 20 ++++ .../Common/View/TitleValueDiffView.swift | 62 ++++++++++++ .../View/Rows/YourVoteRow.swift | 7 +- .../ReferendumVoteConfirmViewLayout.swift | 92 ++++++++++++++++++ .../ReferendumVoteSetupPresenter.swift | 20 +++- .../ReferendumVoteSetupProtocols.swift | 4 +- .../ReferendumVoteSetupViewController.swift | 4 +- .../ReferendumVoteSetupViewLayout.swift | 83 +--------------- .../ReferendumVoteSetupWireframe.swift | 19 +++- 12 files changed, 243 insertions(+), 88 deletions(-) create mode 100644 novawallet/Assets.xcassets/iconGovTransferable.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconGovTransferable.imageset/iconGovTransferable.pdf create mode 100644 novawallet/Common/View/StackTitleValueDiffCell.swift create mode 100644 novawallet/Common/View/TitleValueDiffView.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 1878a9f510..065702eecf 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -932,6 +932,8 @@ 8459A9C827469E4B000D6278 /* AcalaContributionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8459A9C727469E4B000D6278 /* AcalaContributionSource.swift */; }; 8459A9CA2746A1BC000D6278 /* CrowdloanOffchainSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8459A9C92746A1BC000D6278 /* CrowdloanOffchainSubscriber.swift */; }; 8459A9CC2746A1E9000D6278 /* CrowdloanOffchainSubscriptionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8459A9CB2746A1E9000D6278 /* CrowdloanOffchainSubscriptionHandler.swift */; }; + 845AADA12902D02400B5AE96 /* TitleValueDiffView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845AADA02902D02400B5AE96 /* TitleValueDiffView.swift */; }; + 845AADA32902D1EB00B5AE96 /* StackTitleValueDiffCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845AADA22902D1EA00B5AE96 /* StackTitleValueDiffCell.swift */; }; 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811128F429BB0040CE84 /* SupportPallet.swift */; }; 845B811528F43C350040CE84 /* Treasury.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811428F43C350040CE84 /* Treasury.swift */; }; 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811628F43C730040CE84 /* TreasuryProposal.swift */; }; @@ -3836,6 +3838,8 @@ 8459A9C727469E4B000D6278 /* AcalaContributionSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcalaContributionSource.swift; sourceTree = ""; }; 8459A9C92746A1BC000D6278 /* CrowdloanOffchainSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanOffchainSubscriber.swift; sourceTree = ""; }; 8459A9CB2746A1E9000D6278 /* CrowdloanOffchainSubscriptionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanOffchainSubscriptionHandler.swift; sourceTree = ""; }; + 845AADA02902D02400B5AE96 /* TitleValueDiffView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleValueDiffView.swift; sourceTree = ""; }; + 845AADA22902D1EA00B5AE96 /* StackTitleValueDiffCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackTitleValueDiffCell.swift; sourceTree = ""; }; 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; @@ -9592,6 +9596,8 @@ 8468119328E6234B00BF54F1 /* RoundedSegmentedControl.swift */, 84E63C1628FFC69A0093534A /* DiscreteGradientSlider.swift */, 84F76ED729006BC400D7206C /* DiscreteGradientSlider+Style.swift */, + 845AADA02902D02400B5AE96 /* TitleValueDiffView.swift */, + 845AADA22902D1EA00B5AE96 /* StackTitleValueDiffCell.swift */, ); path = View; sourceTree = ""; @@ -14685,6 +14691,7 @@ 845BB8D125E45F1300E5FCDC /* NominateCall.swift in Sources */, 88421057289BBA8D00306F2C /* CurrencyProtocols.swift in Sources */, 842BDB28278C4CE500AB4B5A /* DAppBrowserWaitingAuthState.swift in Sources */, + 845AADA32902D1EB00B5AE96 /* StackTitleValueDiffCell.swift in Sources */, 848DAF042822B7FE00D56F55 /* ParachainStakingCollatorService+Fetch.swift in Sources */, 840689FC26321F2700A017B1 /* StorageQuery.swift in Sources */, 8423ADD026B2C38600057EDD /* ImportantFlowViewFactory.swift in Sources */, @@ -16484,6 +16491,7 @@ 255D7AEBA45EFA5324D92371 /* DAppListPresenter.swift in Sources */, 2C9A416905C692DCFA74A0D6 /* DAppListInteractor.swift in Sources */, CE773CEC15A83AA6D0B404B8 /* DAppListViewController.swift in Sources */, + 845AADA12902D02400B5AE96 /* TitleValueDiffView.swift in Sources */, A07A987DE3047AF1A786D511 /* DAppListViewLayout.swift in Sources */, 8DF76D04C127E0048B253343 /* DAppListViewFactory.swift in Sources */, 848F8B242864448900204BC4 /* TransferSetupPresenterFactory+OnChain.swift in Sources */, diff --git a/novawallet/Assets.xcassets/iconGovTransferable.imageset/Contents.json b/novawallet/Assets.xcassets/iconGovTransferable.imageset/Contents.json new file mode 100644 index 0000000000..0ee609ba44 --- /dev/null +++ b/novawallet/Assets.xcassets/iconGovTransferable.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "iconGovTransferable.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/iconGovTransferable.imageset/iconGovTransferable.pdf b/novawallet/Assets.xcassets/iconGovTransferable.imageset/iconGovTransferable.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b0e314774089b8209db34b30ad0ec1eb61beb88e GIT binary patch literal 3259 zcmc&$OK;pZ5We$Q@M0h-5Q%S6Kwuz#qG*FSyFCO5dXQzs-egyDCAo0&>oY@9l(bqm z^&tokHun?f{gE?AS7#Tmcw!0Rl+pV7GokeLYnuM`^}eL(hj-VX%c27eR{CdI-FA0W zz`<33E}Qz{ej?z1_usrsFSrJMO*s5&nho&f7 zZ{qy1yIgm9SN6Yz|5xOcCCV{abkH@LUhdL!{(QOPhgr1uBX3>mi$A|v)h(LeNdKQB5vY0n<&YR;&e1s>_|Mf z+_XhSRAQL4Tu_%trkKj;4lrq%k{MuHS}6pTNtOvA+!V3eWm=DN1$fD=LQExAFs2;c zl2_oKc9J^)l{40AI)ylM+9=3Zkd%qDT4bD}HpLv;l!;M-fd-aXXV9;RKukPC?f4<=akamh)tvtnKok(h-qtP!P_L$Y8Jc$*X&;KE`d~K4oeVHJ3&JJ zqg*T#`n6AkEx99~ej^om?`bGzG>lvt`50*k25kn_hjL}YSq`=Qr7X<;Ckyq0h2j7U zvjqz?y3azC3yf0-Sm^1FEJV-ZxxgEP>_!&CW?-ROvQUAE1q<=qoQ0qyLV<;umwb|i zdSIdO%$&0@qx&qxH^Q@!k8%YGob!I;1;l^Wc#%l>=da`rGPjFM?e!0PZ5z(>9!0kTJ z<+c+v3T;REL)fUtzdru)IZ$>iTVHk|MXWm9-^r{JrWD`SKR`>wN{{_|Z))hf|N3p- ze(?hRpo2eWW65%G=#li2BIUyT^VF$;r!e@u+1}sfKUO`^$$g%P&V;u!g9-sRi+b}swal%EKroRj|k;$LdCh6xAou+RW53OCd* zZW%<5YXZUCGlzs=OGxhP5_&0UmZyw{TQ;*OoPfK!2W6whuE{ssvLTq>-_IbqFWP!n szN9ZUH!u4Xr>nY#{9^iiz0&pOTZy@V, StackTableViewCellProtocol { + convenience init() { + self.init(frame: .zero) + } + + override init(frame: CGRect) { + super.init(frame: frame) + + configureStyle() + } + + private func configureStyle() { + preferredHeight = 44.0 + borderView.strokeColor = R.color.colorWhite8()! + + isUserInteractionEnabled = false + } +} diff --git a/novawallet/Common/View/TitleValueDiffView.swift b/novawallet/Common/View/TitleValueDiffView.swift new file mode 100644 index 0000000000..6c745021d3 --- /dev/null +++ b/novawallet/Common/View/TitleValueDiffView.swift @@ -0,0 +1,62 @@ +import UIKit + +typealias TitleValueDiffView = GenericTitleValueView< + IconDetailsView, + GenericPairValueView, IconDetailsView> +> + +extension TitleValueDiffView: BindableView { + typealias TModel = ReferendumLockTransitionViewModel + + func bind(viewModel: ReferendumLockTransitionViewModel) { + let viewTop = valueView.fView + viewTop.fView.detailsLabel.text = viewModel.fromValue + viewTop.sView.text = viewModel.toValue + + let viewBottom = valueView.sView + + if let change = viewModel.change { + viewBottom.isHidden = false + + viewBottom.detailsLabel.text = change.value + + let icon = change.isIncrease ? R.image.iconAmountInc() : R.image.iconAmountDec() + viewBottom.imageView.image = icon + } else { + viewBottom.isHidden = true + } + + setNeedsLayout() + } + + func applyDefaultStyle() { + titleView.spacing = 8.0 + titleView.mode = .iconDetails + titleView.iconWidth = 16.0 + titleView.detailsLabel.textColor = R.color.colorTransparentText() + titleView.detailsLabel.font = .regularFootnote + titleView.detailsLabel.numberOfLines = 1 + + valueView.setVerticalAndSpacing(0.0) + valueView.stackView.alignment = .trailing + + let mappingView = valueView.fView + mappingView.setHorizontalAndSpacing(4.0) + mappingView.fView.iconWidth = 12.0 + mappingView.fView.spacing = 4.0 + mappingView.fView.mode = .detailsIcon + mappingView.fView.detailsLabel.textColor = R.color.colorTransparentText() + mappingView.fView.detailsLabel.font = .regularFootnote + mappingView.fView.detailsLabel.numberOfLines = 1 + mappingView.fView.imageView.image = R.image.iconGovLockTransition() + mappingView.sView.textColor = R.color.colorWhite() + mappingView.sView.font = .regularFootnote + + let changesView = valueView.sView + changesView.mode = .iconDetails + changesView.spacing = 0.0 + changesView.detailsLabel.textColor = R.color.colorNovaBlue() + changesView.detailsLabel.font = .caption1 + changesView.detailsLabel.numberOfLines = 1 + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift index 102a52bb8d..27f9ada266 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/YourVoteRow.swift @@ -6,15 +6,20 @@ final class YourVoteRow: RowView ReferendumNewVote? { + private func deriveNewVote(isAye: Bool = true) -> ReferendumNewVote? { let amount = inputResult?.absoluteValue(from: balanceMinusFee()) ?? 0 guard @@ -210,7 +210,7 @@ final class ReferendumVoteSetupPresenter { let voteAction = ReferendumVoteAction( amount: amountInPlank, conviction: conviction, - isAye: true + isAye: isAye ) return ReferendumNewVote(index: referendumIndex, voteAction: voteAction) @@ -279,9 +279,21 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { refreshLockDiff() } - func proceedNay() {} + func proceedNay() { + guard let newVote = deriveNewVote(isAye: false) else { + return + } + + wireframe.showConfirmation(from: view, vote: newVote) + } - func proceedAye() {} + func proceedAye() { + guard let newVote = deriveNewVote(isAye: true) else { + return + } + + wireframe.showConfirmation(from: view, vote: newVote) + } } extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index 9d77674afd..d4cb34f423 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -26,4 +26,6 @@ protocol ReferendumVoteSetupInteractorInputProtocol: ReferendumVoteInteractorInp protocol ReferendumVoteSetupInteractorOutputProtocol: ReferendumVoteInteractorOutputProtocol {} -protocol ReferendumVoteSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, FeeRetryable {} +protocol ReferendumVoteSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, FeeRetryable { + func showConfirmation(from view: ReferendumVoteSetupViewProtocol?, vote: ReferendumNewVote) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift index 5816b4203a..378d1fe0cc 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -159,11 +159,11 @@ extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol { } func didReceiveLockedAmount(viewModel: ReferendumLockTransitionViewModel) { - rootView.bindLockAmount(viewModel: viewModel) + rootView.lockedAmountView.bind(viewModel: viewModel) } func didReceiveLockedPeriod(viewModel: ReferendumLockTransitionViewModel) { - rootView.bindLockPeriod(viewModel: viewModel) + rootView.lockedPeriodView.bind(viewModel: viewModel) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index 6ad9cc4d94..42c17a34a7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -1,9 +1,6 @@ import UIKit final class ReferendumVoteSetupViewLayout: UIView { - typealias MappingView = GenericPairValueView - typealias ChangesView = GenericPairValueView - let containerView: ScrollableContainerView = { let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) view.stackView.layoutMargins = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 0.0, right: 16.0) @@ -42,21 +39,17 @@ final class ReferendumVoteSetupViewLayout: UIView { lockedAmountView.titleView.detailsLabel } - let lockedAmountView: GenericTitleValueView = { - let view = ReferendumVoteSetupViewLayout.createMultiValueView() + let lockedAmountView: TitleValueDiffView = .create { view in view.titleView.imageView.image = R.image.iconGovAmountLock() - return view - }() + } var lockPeriodTitleLabel: UILabel { lockedPeriodView.titleView.detailsLabel } - let lockedPeriodView: GenericTitleValueView = { - let view = ReferendumVoteSetupViewLayout.createMultiValueView() + let lockedPeriodView: TitleValueDiffView = .create { view in view.titleView.imageView.image = R.image.iconGovPeriodLock() - return view - }() + } override init(frame: CGRect) { super.init(frame: frame) @@ -71,40 +64,6 @@ final class ReferendumVoteSetupViewLayout: UIView { fatalError("init(coder:) has not been implemented") } - func bindLockAmount(viewModel: ReferendumLockTransitionViewModel) { - bindLockTrasition(for: viewModel, view: lockedAmountView) - - setNeedsLayout() - } - - func bindLockPeriod(viewModel: ReferendumLockTransitionViewModel) { - bindLockTrasition(for: viewModel, view: lockedPeriodView) - - setNeedsLayout() - } - - private func bindLockTrasition( - for viewModel: ReferendumLockTransitionViewModel, - view: GenericTitleValueView - ) { - let viewTop = view.valueView.fView - viewTop.fView.detailsLabel.text = viewModel.fromValue - viewTop.sView.text = viewModel.toValue - - let viewBottom = view.valueView.sView - - if let change = viewModel.change { - viewBottom.isHidden = false - - viewBottom.detailsLabel.text = change.value - - let icon = change.isIncrease ? R.image.iconAmountInc() : R.image.iconAmountDec() - viewBottom.imageView.image = icon - } else { - viewBottom.isHidden = true - } - } - private func setupLayout() { addSubview(nayButton) nayButton.snp.makeConstraints { make in @@ -163,38 +122,4 @@ final class ReferendumVoteSetupViewLayout: UIView { make.height.equalTo(34.0) } } - - static func createMultiValueView() -> GenericTitleValueView { - let view = GenericTitleValueView() - view.titleView.spacing = 8.0 - view.titleView.mode = .iconDetails - view.titleView.iconWidth = 16.0 - view.titleView.detailsLabel.textColor = R.color.colorTransparentText() - view.titleView.detailsLabel.font = .regularFootnote - view.titleView.detailsLabel.numberOfLines = 1 - - view.valueView.setVerticalAndSpacing(0.0) - view.valueView.stackView.alignment = .trailing - - let mappingView = view.valueView.fView - mappingView.setHorizontalAndSpacing(4.0) - mappingView.fView.iconWidth = 12.0 - mappingView.fView.spacing = 4.0 - mappingView.fView.mode = .detailsIcon - mappingView.fView.detailsLabel.textColor = R.color.colorTransparentText() - mappingView.fView.detailsLabel.font = .regularFootnote - mappingView.fView.detailsLabel.numberOfLines = 1 - mappingView.fView.imageView.image = R.image.iconGovLockTransition() - mappingView.sView.textColor = R.color.colorWhite() - mappingView.sView.font = .regularFootnote - - let changesView = view.valueView.sView - changesView.mode = .iconDetails - changesView.spacing = 0.0 - changesView.detailsLabel.textColor = R.color.colorNovaBlue() - changesView.detailsLabel.font = .caption1 - changesView.detailsLabel.numberOfLines = 1 - - return view - } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift index 9b8f1b4f23..f4bf406d26 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift @@ -1,3 +1,20 @@ import Foundation -final class ReferendumVoteSetupWireframe: ReferendumVoteSetupWireframeProtocol {} +final class ReferendumVoteSetupWireframe: ReferendumVoteSetupWireframeProtocol { + let state: GovernanceSharedState + + init(state: GovernanceSharedState) { + self.state = state + } + + func showConfirmation(from view: ReferendumVoteSetupViewProtocol?, vote: ReferendumNewVote) { + guard let confirmView = ReferendumVoteConfirmViewFactory.createView( + for: state, + newVote: vote + ) else { + return + } + + view?.controller.navigationController?.pushViewController(confirmView.controller, animated: true) + } +} From 67cddab840f434d0fbab934fe3eaf3787dfe53da Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 21 Oct 2022 21:07:00 +0300 Subject: [PATCH 082/229] init --- novawallet.xcodeproj/project.pbxproj | 4 + .../ReferendumDecidingFunctionProtocol.swift | 1 + .../ReferendumFullDetailsInteractor.swift | 56 +++++++ .../ReferendumFullDetailsPresenter.swift | 134 +++++++++++++++++ .../ReferendumFullDetailsProtocols.swift | 23 ++- .../ReferendumFullDetailsViewController.swift | 30 +++- .../ReferendumFullDetailsViewFactory.swift | 2 + .../ReferendumFullDetailsViewLayout.swift | 142 ++++++++++++++++++ 8 files changed, 389 insertions(+), 3 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 7b9ea677b1..9f26d8d675 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2199,6 +2199,7 @@ 880855FC28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */; }; 88107D5F290133F8001AB0B0 /* RoundedView+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */; }; 88107D6129015FAB001AB0B0 /* TrackTagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */; }; + 8824D4222902D92F0022D778 /* ReferendumFullDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */; }; 882808C829009CA500AE8089 /* DotsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C729009CA500AE8089 /* DotsView.swift */; }; 882808CA29009CDC00AE8089 /* UIView+frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C929009CDC00AE8089 /* UIView+frame.swift */; }; 8828C05828B4A67000555CB6 /* Prism.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8828C05728B4A67000555CB6 /* Prism.swift */; }; @@ -5090,6 +5091,7 @@ 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RoundedView+Styles.swift"; sourceTree = ""; }; 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackTagsView.swift; sourceTree = ""; }; 8821119C96944A0E3526E93A /* StakingRedeemViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRedeemViewFactory.swift; sourceTree = ""; }; + 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsInteractor.swift; sourceTree = ""; }; 882808C729009CA500AE8089 /* DotsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotsView.swift; sourceTree = ""; }; 882808C929009CDC00AE8089 /* UIView+frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+frame.swift"; sourceTree = ""; }; 8828C05728B4A67000555CB6 /* Prism.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Prism.swift; sourceTree = ""; }; @@ -12034,6 +12036,7 @@ 3C535E8504943299B3E4A8EB /* ReferendumFullDetailsViewController.swift */, 57CDCB8CF3D8EBE5DA7A5A30 /* ReferendumFullDetailsViewLayout.swift */, 369C65964F4D7E8D02EEC5EC /* ReferendumFullDetailsViewFactory.swift */, + 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */, ); path = ReferendumFullDetails; sourceTree = ""; @@ -16719,6 +16722,7 @@ 7C0135CA49EF6B535030643E /* ParaStkYieldBoostSetupPresenter.swift in Sources */, 21B297239CC294307EF20B58 /* ParaStkYieldBoostSetupInteractor.swift in Sources */, AE180C8B30831C9BAA39763A /* ParaStkYieldBoostSetupViewController.swift in Sources */, + 8824D4222902D92F0022D778 /* ReferendumFullDetailsInteractor.swift in Sources */, 88B1862A28EF30A600D49854 /* YourVoteView.swift in Sources */, C19EF49636E698D87D5D18FA /* ParaStkYieldBoostSetupViewLayout.swift in Sources */, B3E567D46F54E8E735792FE1 /* ParaStkYieldBoostSetupViewFactory.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift index 71dd8d1066..a2e64213f2 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumDecidingFunctionProtocol.swift @@ -1,6 +1,7 @@ import Foundation protocol ReferendumDecidingFunctionProtocol { + var curve: Referenda.Curve { get } func calculateThreshold(for block: BlockNumber) -> Decimal? } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift new file mode 100644 index 0000000000..517cde47db --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift @@ -0,0 +1,56 @@ +import UIKit +import SubstrateSdk + +final class ReferendumFullDetailsInteractor { + weak var presenter: ReferendumFullDetailsInteractorOutputProtocol? + let chain: ChainModel + let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol + let currencyManager: CurrencyManagerProtocol + let operationQueue: OperationQueue + private var priceProvider: AnySingleValueProvider? + + init( + chain: ChainModel, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + currencyManager: CurrencyManagerProtocol, + operationQueue: OperationQueue + ) { + self.chain = chain + self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory + self.operationQueue = operationQueue + self.currencyManager = currencyManager + } + + private func makeSubscriptions() { + if let priceId = chain.utilityAsset()?.priceId { + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } + } +} + +extension ReferendumFullDetailsInteractor: ReferendumFullDetailsInteractorInputProtocol { + func setup() { + makeSubscriptions() + } +} + +extension ReferendumFullDetailsInteractor: PriceLocalSubscriptionHandler, PriceLocalStorageSubscriber { + func handlePrice(result: Result, priceId _: AssetModel.PriceId) { + switch result { + case let .success(price): + presenter?.didReceive(price: price) + case let .failure(error): + presenter?.didReceive(error: .priceFailed(error)) + } + } +} + +extension ReferendumFullDetailsInteractor: SelectedCurrencyDepending { + func applyCurrency() { + if presenter != nil { + if let priceId = chain.utilityAsset()?.priceId { + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index 512d64548f..df1ff0951f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -1,8 +1,10 @@ import Foundation +import SubstrateSdk final class ReferendumFullDetailsPresenter { weak var view: ReferendumFullDetailsViewProtocol? let wireframe: ReferendumFullDetailsWireframeProtocol + let chainIconGenerator: IconGenerating let chain: ChainModel let referendum: ReferendumLocal @@ -11,6 +13,7 @@ final class ReferendumFullDetailsPresenter { init( wireframe: ReferendumFullDetailsWireframeProtocol, + chainIconGenerator: IconGenerating, chain: ChainModel, referendum: ReferendumLocal, actionDetails: ReferendumActionLocal, @@ -21,9 +24,140 @@ final class ReferendumFullDetailsPresenter { self.referendum = referendum self.actionDetails = actionDetails self.identities = identities + self.chainIconGenerator = chainIconGenerator + } + + private func updateView() { + guard let view = view else { + return + } + getProposer().map { + view.didReceive(proposerModel: .init( + title: "Proposer", + model: .init( + details: $0.name, + imageViewModel: $0.icon + ) + )) + } + let approvalCurveModel = referendum.state.approvalCurve.map { + TitleWithSubtitleViewModel( + title: "Approve Curve", + subtitle: $0.displayName + ) + } + let supportCurveModel = referendum.state.supportCurve.map { + TitleWithSubtitleViewModel( + title: "Support Curve", + subtitle: $0.displayName + ) + } + let callHashModel = referendum.state.callHash.map { + TitleWithSubtitleViewModel( + title: "Call Hash", + subtitle: $0 + ) + } + + view.didReceive( + approveCurve: approvalCurveModel, + supportCurve: supportCurveModel, + callHash: callHashModel + ) + } + + private func getProposer() -> (name: String, icon: ImageViewModelProtocol?)? { + guard let proposer = referendum.proposer, + let proposerAddress = try? proposer.toAddress(using: chain.chainFormat) else { + return nil + } + + let chainAccountIcon = icon( + generator: chainIconGenerator, + from: proposer + ) + + let name = identities[proposerAddress]?.displayName ?? proposerAddress + + return (name: name, icon: chainAccountIcon) + } + + private func icon( + generator: IconGenerating, + from imageData: Data? + ) -> DrawableIconViewModel? { + guard let data = imageData, + let icon = try? generator.generateFromAccountId(data) else { + return nil + } + + return DrawableIconViewModel(icon: icon) } } extension ReferendumFullDetailsPresenter: ReferendumFullDetailsPresenterProtocol { func setup() {} } + +extension ReferendumStateLocal { + var approvalCurve: Referenda.Curve? { + switch voting { + case let .supportAndVotes(model): + return model.approvalFunction?.curve + case .none: + return nil + } + } + + var supportCurve: Referenda.Curve? { + switch voting { + case let .supportAndVotes(model): + return model.supportFunction?.curve + case .none: + return nil + } + } + + var callHash: String? { + switch proposal { + case let .lookup(lookup): + return String(data: lookup.hash, encoding: .utf8) + case let .legacy(hash): + return String(data: hash, encoding: .utf8) + case .inline, .unknown, .none: + return nil + } + } + + var voting: Voting? { + switch self { + case let .preparing(model): + return model.voting + case let .deciding(model): + return model.voting + case .approved, + .rejected, + .cancelled, + .timedOut, + .killed, + .executed: + return nil + } + } +} + +extension Referenda.Curve { + // TODO: localize? + var displayName: String { + switch self { + case .linearDecreasing: + return "Linear Decreasing" + case .reciprocal: + return "Reciprocal" + case .steppedDecreasing: + return "Stepped Decreasing" + case .unknown: + return "Unknown" + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift index e11b42985f..4d35ea0b72 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift @@ -1,7 +1,28 @@ -protocol ReferendumFullDetailsViewProtocol: ControllerBackedProtocol {} +protocol ReferendumFullDetailsViewProtocol: ControllerBackedProtocol { + func didReceive(proposerModel: ProposerTableCell.Model?) + func didReceive(json: String?, jsonTitle: String) + func didReceive( + approveCurve: TitleWithSubtitleViewModel?, + supportCurve: TitleWithSubtitleViewModel?, + callHash: TitleWithSubtitleViewModel? + ) +} protocol ReferendumFullDetailsPresenterProtocol: AnyObject { func setup() } +protocol ReferendumFullDetailsInteractorOutputProtocol: AnyObject { + func didReceive(price: PriceData?) + func didReceive(error: ReferendumFullDetailsError) +} + protocol ReferendumFullDetailsWireframeProtocol: AnyObject {} + +protocol ReferendumFullDetailsInteractorInputProtocol: AnyObject { + func setup() +} + +enum ReferendumFullDetailsError: Error { + case priceFailed(Error) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift index c9e80267d6..15dab24b36 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift @@ -1,6 +1,6 @@ import UIKit -final class ReferendumFullDetailsViewController: UIViewController { +final class ReferendumFullDetailsViewController: UIViewController, ViewHolder { typealias RootViewType = ReferendumFullDetailsViewLayout let presenter: ReferendumFullDetailsPresenterProtocol @@ -26,4 +26,30 @@ final class ReferendumFullDetailsViewController: UIViewController { } } -extension ReferendumFullDetailsViewController: ReferendumFullDetailsViewProtocol {} +extension ReferendumFullDetailsViewController: ReferendumFullDetailsViewProtocol { + func didReceive(proposerModel: ProposerTableCell.Model?) { + rootView.updateProposerCell(proposerModel: proposerModel) + } + + func didReceive(json: String?, jsonTitle: String) { + if let json = json { + rootView.jsonView.view.text = json + } else { + // todo + } + rootView.jsonTitle.text = jsonTitle + } + + func didReceive( + approveCurve: TitleWithSubtitleViewModel?, + supportCurve: TitleWithSubtitleViewModel?, + callHash: TitleWithSubtitleViewModel? + ) { + rootView.approveCurve.titleLabel.text = approveCurve?.title + rootView.approveCurve.detailsLabel.text = approveCurve?.subtitle + rootView.supportCurve.titleLabel.text = supportCurve?.title + rootView.supportCurve.detailsLabel.text = supportCurve?.subtitle + rootView.callHash.titleLabel.text = callHash?.title + rootView.callHash.detailsLabel.text = callHash?.subtitle + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift index bf3e319b87..fb5baeae1c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift @@ -1,4 +1,5 @@ import Foundation +import SubstrateSdk struct ReferendumFullDetailsViewFactory { static func createView( @@ -15,6 +16,7 @@ struct ReferendumFullDetailsViewFactory { let presenter = ReferendumFullDetailsPresenter( wireframe: wireframe, + chainIconGenerator: PolkadotIconGenerator(), chain: chain, referendum: referendum, actionDetails: actionDetails, diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index 46b36a5de4..94b1e4a95b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -1,12 +1,154 @@ import UIKit final class ReferendumFullDetailsViewLayout: UIView { + let containerView: ScrollableContainerView = { + let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) + view.stackView.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 24, right: 16) + view.stackView.isLayoutMarginsRelativeArrangement = true + view.stackView.alignment = .fill + return view + }() + + let accountDetailsTableView = StackTableView() + var referendumDetailsTableView = StackTableView() + + var proposerTableCell: StackInfoTableCell? + let depositTableCell = StackTitleMultiValueCell() + + let approveCurve = StackTableCell() + let supportCurve = StackTableCell() + let callHash: StackInfoTableCell = .create { + $0.detailsLabel.lineBreakMode = .byTruncatingMiddle + } + + let jsonTitle: UILabel = .init(style: .rowTitle) + let jsonView: BlurredView = .create { + $0.view.allowsEditingTextAttributes = false + } + + override init(frame: CGRect) { + super.init(frame: frame) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setup() { + addSubview(containerView) + containerView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + + containerView.stackView.spacing = 8 + containerView.stackView.addArrangedSubview(accountDetailsTableView) + containerView.stackView.addArrangedSubview(referendumDetailsTableView) + + accountDetailsTableView.addArrangedSubview(depositTableCell) + referendumDetailsTableView.addArrangedSubview(approveCurve) + referendumDetailsTableView.addArrangedSubview(supportCurve) + referendumDetailsTableView.addArrangedSubview(callHash) + containerView.stackView.addArrangedSubview(jsonTitle) + containerView.stackView.addArrangedSubview(jsonView) + } + + func updateProposerCell(proposerModel: ProposerTableCell.Model?) { + guard let proposerModel = proposerModel else { + proposerTableCell?.removeFromSuperview() + proposerTableCell = nil + return + } + if proposerTableCell == nil { + let proposerTableCell = createStackInfoCell(title: proposerModel.title) + accountDetailsTableView.insertArrangedSubview(proposerTableCell, at: 0) + self.proposerTableCell = proposerTableCell + } + + proposerTableCell?.bind(viewModel: proposerModel.model) + } + + private func createStackInfoCell(title: String) -> StackInfoTableCell { + let proposerCell = StackInfoTableCell() + proposerCell.rowContentView.valueView.mode = .iconDetails + proposerCell.rowContentView.titleView.text = title + return proposerCell + } +} + +typealias ProposerTableCell = StackInfoTableCell +extension ProposerTableCell { + struct Model { + let title: String + let model: StackCellViewModel? + } +} + +typealias AmountSpendDetailsTableView = StackTableView + +extension AmountSpendDetailsTableView { + struct Model { + let beneficiary: BeneficiaryModel + let requestedAmount: RequestedAmountModel + } + + struct BeneficiaryModel { + let title: String + let model: StackCellViewModel? + } + + struct RequestedAmountModel { + let title: String + let model: StackCellViewModel? + } +} + +class BlurredView: UIView where TContentView: UIView { + let view: TContentView = .init() + let backgroundBlurView = TriangularedBlurView() + + var contentInsets: UIEdgeInsets = .init(top: 0, left: 16, bottom: 0, right: 16) { + didSet { + updateLayout() + } + } + + var innerInsets: UIEdgeInsets = .zero { + didSet { + updateLayout() + } + } + override init(frame: CGRect) { super.init(frame: frame) + + backgroundColor = .clear + setupLayout() } @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } + + private func setupLayout() { + addSubview(backgroundBlurView) + backgroundBlurView.snp.makeConstraints { + $0.edges.equalToSuperview().inset(contentInsets) + } + + backgroundBlurView.addSubview(view) + view.snp.makeConstraints { + $0.edges.equalToSuperview().inset(innerInsets) + } + } + + private func updateLayout() { + backgroundBlurView.snp.updateConstraints { + $0.edges.equalToSuperview().inset(contentInsets) + } + view.snp.updateConstraints { + $0.edges.equalToSuperview().inset(innerInsets) + } + } } From 1dda8c8af165df724367b09e2fa1a6ca21d76f47 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 21 Oct 2022 23:16:36 +0300 Subject: [PATCH 083/229] added formating json, added deposit and price --- novawallet.xcodeproj/project.pbxproj | 12 ++ .../PrettyPrintedJSONOperationFactory.swift | 43 ++++++ .../DAppTxDetailsInteractor.swift | 36 ++--- .../DAppTxDetailsViewFactory.swift | 3 +- .../ReferendumDetails/View/BlurredView.swift | 51 +++++++ .../ReferendumFullDetailsInteractor.swift | 40 +++++- .../ReferendumFullDetailsPresenter.swift | 79 +++-------- .../ReferendumFullDetailsProtocols.swift | 5 + .../ReferendumFullDetailsViewController.swift | 18 ++- .../ReferendumFullDetailsViewFactory.swift | 13 +- .../ReferendumFullDetailsViewLayout.swift | 127 +++++++++--------- .../ReferendumStateLocal+Presenter.swift | 62 +++++++++ 12 files changed, 333 insertions(+), 156 deletions(-) create mode 100644 novawallet/Common/Operation/PrettyPrintedJSONOperationFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 9f26d8d675..8cdbd2eeff 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2200,6 +2200,9 @@ 88107D5F290133F8001AB0B0 /* RoundedView+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */; }; 88107D6129015FAB001AB0B0 /* TrackTagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */; }; 8824D4222902D92F0022D778 /* ReferendumFullDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */; }; + 8824D424290324260022D778 /* PrettyPrintedJSONOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D423290324260022D778 /* PrettyPrintedJSONOperationFactory.swift */; }; + 8824D42629032B410022D778 /* BlurredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D42529032B410022D778 /* BlurredView.swift */; }; + 8824D42829032BF60022D778 /* ReferendumStateLocal+Presenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D42729032BF60022D778 /* ReferendumStateLocal+Presenter.swift */; }; 882808C829009CA500AE8089 /* DotsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C729009CA500AE8089 /* DotsView.swift */; }; 882808CA29009CDC00AE8089 /* UIView+frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882808C929009CDC00AE8089 /* UIView+frame.swift */; }; 8828C05828B4A67000555CB6 /* Prism.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8828C05728B4A67000555CB6 /* Prism.swift */; }; @@ -5092,6 +5095,9 @@ 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackTagsView.swift; sourceTree = ""; }; 8821119C96944A0E3526E93A /* StakingRedeemViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRedeemViewFactory.swift; sourceTree = ""; }; 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsInteractor.swift; sourceTree = ""; }; + 8824D423290324260022D778 /* PrettyPrintedJSONOperationFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrettyPrintedJSONOperationFactory.swift; sourceTree = ""; }; + 8824D42529032B410022D778 /* BlurredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurredView.swift; sourceTree = ""; }; + 8824D42729032BF60022D778 /* ReferendumStateLocal+Presenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReferendumStateLocal+Presenter.swift"; sourceTree = ""; }; 882808C729009CA500AE8089 /* DotsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotsView.swift; sourceTree = ""; }; 882808C929009CDC00AE8089 /* UIView+frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+frame.swift"; sourceTree = ""; }; 8828C05728B4A67000555CB6 /* Prism.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Prism.swift; sourceTree = ""; }; @@ -9379,6 +9385,7 @@ 848B2FFF286EDE3800465BA2 /* ParaIdOperationFactory.swift */, 847999A8288862A500D1BAD2 /* MetaAccountOperationFactory+Secrets.swift */, 84A58FD828A10ABD003F6ABF /* MultipartQrOperationFactory.swift */, + 8824D423290324260022D778 /* PrettyPrintedJSONOperationFactory.swift */, ); path = Operation; sourceTree = ""; @@ -12037,6 +12044,7 @@ 57CDCB8CF3D8EBE5DA7A5A30 /* ReferendumFullDetailsViewLayout.swift */, 369C65964F4D7E8D02EEC5EC /* ReferendumFullDetailsViewFactory.swift */, 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */, + 8824D42729032BF60022D778 /* ReferendumStateLocal+Presenter.swift */, ); path = ReferendumFullDetails; sourceTree = ""; @@ -12134,6 +12142,7 @@ 88FAE78728FCF8E200130B47 /* ReferendumDetailsTitleView.swift */, 88F34FD128FF045400712BDE /* BindableView.swift */, 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */, + 8824D42529032B410022D778 /* BlurredView.swift */, ); path = View; sourceTree = ""; @@ -14848,6 +14857,7 @@ 8887813E28B7AA3100E7290F /* RoundedIconTitleCollectionHeaderView.swift in Sources */, 88C017E628C60A65003B2D28 /* AssetLockMapper.swift in Sources */, AEA2C1BA2681E9C50069492E /* ValidatorSearchInteractor.swift in Sources */, + 8824D42629032B410022D778 /* BlurredView.swift in Sources */, 84585A2F251BFC8400390F7A /* TriangularedButton+Style.swift in Sources */, 84C6801A24D75E2A00006BF5 /* BorderedSubtitleActionView+Inspectable.swift in Sources */, 84FACCD425F8B07B00F32ED4 /* ReceiveAccountViewModel.swift in Sources */, @@ -15132,6 +15142,7 @@ 846A835F28B8D94300D92892 /* MessageSheetNoContentView.swift in Sources */, 845B811F28F451A40040CE84 /* Gov2ActionOperationFactory.swift in Sources */, 84754CA22513DB8800854599 /* EmptyAccountIcon.swift in Sources */, + 8824D424290324260022D778 /* PrettyPrintedJSONOperationFactory.swift in Sources */, AEA0C8C6268131C500F9666F /* InitiatedBondingSelectedValidatorsListWireframe.swift in Sources */, 880059E328EF128000E87B9B /* ReferendumInfoView.swift in Sources */, 84CE69922565244700559427 /* WalletAccountOpenCommand.swift in Sources */, @@ -16010,6 +16021,7 @@ 84F3B27827F4179A00D64CF5 /* PhishingSiteMapper.swift in Sources */, 0678271BE1BA5BBC084F478A /* RecommendedValidatorListWireframe.swift in Sources */, F441BE0E263984DD0096B67B /* BondExtraCall.swift in Sources */, + 8824D42829032BF60022D778 /* ReferendumStateLocal+Presenter.swift in Sources */, 84FB9E20285C5C9E00B42FC0 /* XcmJunction.swift in Sources */, 84EBA4F027AD26A5000AEEAD /* AssetBalanceId.swift in Sources */, 8436B6DC2848998200F24360 /* StakingAccountDetailsViewModelFactory.swift in Sources */, diff --git a/novawallet/Common/Operation/PrettyPrintedJSONOperationFactory.swift b/novawallet/Common/Operation/PrettyPrintedJSONOperationFactory.swift new file mode 100644 index 0000000000..fe3ff14582 --- /dev/null +++ b/novawallet/Common/Operation/PrettyPrintedJSONOperationFactory.swift @@ -0,0 +1,43 @@ +import Foundation +import SubstrateSdk +import RobinHood + +protocol PrettyPrintedJSONOperationFactoryProtocol { + func createProcessingOperation( + for json: JSON + ) -> BaseOperation +} + +final class PrettyPrintedJSONOperationFactory: PrettyPrintedJSONOperationFactoryProtocol { + let preprocessor: JSONPrettyPrinting + + init(preprocessor: JSONPrettyPrinting) { + self.preprocessor = preprocessor + } + + func createProcessingOperation( + for json: JSON + ) -> BaseOperation { + ClosureOperation { [weak self] in + guard let self = self else { + return "" + } + let prettyPrintedJson = self.preprocessor.prettyPrinted(from: json) + + if case let .stringValue(value) = prettyPrintedJson { + return value + } else { + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted + + let data = try encoder.encode(prettyPrintedJson) + + if let displayString = String(data: data, encoding: .utf8) { + return displayString + } else { + throw CommonError.undefined + } + } + } + } +} diff --git a/novawallet/Modules/DApp/DAppTxDetails/DAppTxDetailsInteractor.swift b/novawallet/Modules/DApp/DAppTxDetails/DAppTxDetailsInteractor.swift index 7a714f43e4..f910283d1a 100644 --- a/novawallet/Modules/DApp/DAppTxDetails/DAppTxDetailsInteractor.swift +++ b/novawallet/Modules/DApp/DAppTxDetails/DAppTxDetailsInteractor.swift @@ -6,43 +6,23 @@ final class DAppTxDetailsInteractor { weak var presenter: DAppTxDetailsInteractorOutputProtocol? let txDetails: JSON - let preprocessor: JSONPrettyPrinting + let prettyPrintedJSONOperationFactory: PrettyPrintedJSONOperationFactoryProtocol let operationQueue: OperationQueue - init(txDetails: JSON, preprocessor: JSONPrettyPrinting, operationQueue: OperationQueue) { + init( + txDetails: JSON, + prettyPrintedJSONOperationFactory: PrettyPrintedJSONOperationFactoryProtocol, + operationQueue: OperationQueue + ) { self.txDetails = txDetails - self.preprocessor = preprocessor + self.prettyPrintedJSONOperationFactory = prettyPrintedJSONOperationFactory self.operationQueue = operationQueue } - - private func createProcessingOperation( - for details: JSON, - preprocessor: JSONPrettyPrinting - ) -> BaseOperation { - ClosureOperation { - let prettyPrintedJson = preprocessor.prettyPrinted(from: details) - - if case let .stringValue(value) = prettyPrintedJson { - return value - } else { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - - let data = try encoder.encode(prettyPrintedJson) - - if let displayString = String(data: data, encoding: .utf8) { - return displayString - } else { - throw CommonError.undefined - } - } - } - } } extension DAppTxDetailsInteractor: DAppTxDetailsInteractorInputProtocol { func setup() { - let operation = createProcessingOperation(for: txDetails, preprocessor: preprocessor) + let operation = prettyPrintedJSONOperationFactory.createProcessingOperation(for: txDetails) operation.completionBlock = { [weak self] in DispatchQueue.main.async { diff --git a/novawallet/Modules/DApp/DAppTxDetails/DAppTxDetailsViewFactory.swift b/novawallet/Modules/DApp/DAppTxDetails/DAppTxDetailsViewFactory.swift index 504d692b5b..6f311f987a 100644 --- a/novawallet/Modules/DApp/DAppTxDetails/DAppTxDetailsViewFactory.swift +++ b/novawallet/Modules/DApp/DAppTxDetails/DAppTxDetailsViewFactory.swift @@ -4,9 +4,10 @@ import SoraFoundation struct DAppTxDetailsViewFactory { static func createView(from txDetails: JSON) -> DAppTxDetailsViewProtocol? { + let processingOperationFactory = PrettyPrintedJSONOperationFactory(preprocessor: ExtrinsicJSONProcessor()) let interactor = DAppTxDetailsInteractor( txDetails: txDetails, - preprocessor: ExtrinsicJSONProcessor(), + prettyPrintedJSONOperationFactory: processingOperationFactory, operationQueue: OperationManagerFacade.sharedDefaultQueue ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift new file mode 100644 index 0000000000..efee5287b8 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/BlurredView.swift @@ -0,0 +1,51 @@ +import UIKit + +class BlurredView: UIView where TContentView: UIView { + let view: TContentView = .init() + let backgroundBlurView = TriangularedBlurView() + + var contentInsets: UIEdgeInsets = .init(top: 0, left: 16, bottom: 0, right: 16) { + didSet { + updateLayout() + } + } + + var innerInsets: UIEdgeInsets = .zero { + didSet { + updateLayout() + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + + backgroundColor = .clear + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + addSubview(backgroundBlurView) + backgroundBlurView.snp.makeConstraints { + $0.edges.equalToSuperview().inset(contentInsets) + } + + backgroundBlurView.addSubview(view) + view.snp.makeConstraints { + $0.edges.equalToSuperview().inset(innerInsets) + } + } + + private func updateLayout() { + backgroundBlurView.snp.updateConstraints { + $0.edges.equalToSuperview().inset(contentInsets) + } + view.snp.updateConstraints { + $0.edges.equalToSuperview().inset(innerInsets) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift index 517cde47db..133b5f183a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift @@ -7,30 +7,66 @@ final class ReferendumFullDetailsInteractor { let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let currencyManager: CurrencyManagerProtocol let operationQueue: OperationQueue + let processingOperationFactory: PrettyPrintedJSONOperationFactoryProtocol + let referendumAction: ReferendumActionLocal + private var priceProvider: AnySingleValueProvider? init( chain: ChainModel, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, currencyManager: CurrencyManagerProtocol, + processingOperationFactory: PrettyPrintedJSONOperationFactoryProtocol, + referendumAction: ReferendumActionLocal, operationQueue: OperationQueue ) { + self.processingOperationFactory = processingOperationFactory self.chain = chain + self.referendumAction = referendumAction self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory self.operationQueue = operationQueue self.currencyManager = currencyManager } private func makeSubscriptions() { - if let priceId = chain.utilityAsset()?.priceId { - priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + guard let priceId = chain.utilityAsset()?.priceId else { + return + } + + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } + + private func formatJSON() { + guard let call = referendumAction.call else { + presenter?.didReceive(error: .emptyJSON) + return } + let processingOperation = processingOperationFactory.createProcessingOperation(for: call.args) + processingOperation.completionBlock = { [weak self] in + guard let self = self else { + return + } + do { + let result = try processingOperation.extractNoCancellableResultData() + DispatchQueue.main.async { + self.presenter?.didReceive(json: result) + } + } catch { + DispatchQueue.main.async { + self.presenter?.didReceive(json: nil) + self.presenter?.didReceive(error: .processingJSON(error)) + } + } + } + + operationQueue.addOperation(processingOperation) } } extension ReferendumFullDetailsInteractor: ReferendumFullDetailsInteractorInputProtocol { func setup() { makeSubscriptions() + formatJSON() } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index df1ff0951f..41a516eb5a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -4,14 +4,18 @@ import SubstrateSdk final class ReferendumFullDetailsPresenter { weak var view: ReferendumFullDetailsViewProtocol? let wireframe: ReferendumFullDetailsWireframeProtocol + let interactor: ReferendumFullDetailsInteractorInputProtocol let chainIconGenerator: IconGenerating let chain: ChainModel let referendum: ReferendumLocal let actionDetails: ReferendumActionLocal let identities: [AccountAddress: AccountIdentity] + private var price: PriceData? + private var json: String? init( + interactor: ReferendumFullDetailsInteractorInputProtocol, wireframe: ReferendumFullDetailsWireframeProtocol, chainIconGenerator: IconGenerating, chain: ChainModel, @@ -19,6 +23,7 @@ final class ReferendumFullDetailsPresenter { actionDetails: ReferendumActionLocal, identities: [AccountAddress: AccountIdentity] ) { + self.interactor = interactor self.wireframe = wireframe self.chain = chain self.referendum = referendum @@ -93,71 +98,31 @@ final class ReferendumFullDetailsPresenter { return DrawableIconViewModel(icon: icon) } + + private func updatePriceDependentViews() { + view?.didReceive(deposit: .init(topValue: "3.33333 KSM", + bottomValue: "$200"), + title: "Deposit") + } } extension ReferendumFullDetailsPresenter: ReferendumFullDetailsPresenterProtocol { - func setup() {} -} - -extension ReferendumStateLocal { - var approvalCurve: Referenda.Curve? { - switch voting { - case let .supportAndVotes(model): - return model.approvalFunction?.curve - case .none: - return nil - } - } - - var supportCurve: Referenda.Curve? { - switch voting { - case let .supportAndVotes(model): - return model.supportFunction?.curve - case .none: - return nil - } + func setup() { + interactor.setup() } +} - var callHash: String? { - switch proposal { - case let .lookup(lookup): - return String(data: lookup.hash, encoding: .utf8) - case let .legacy(hash): - return String(data: hash, encoding: .utf8) - case .inline, .unknown, .none: - return nil - } +extension ReferendumFullDetailsPresenter: ReferendumFullDetailsInteractorOutputProtocol { + func didReceive(price: PriceData?) { + self.price = price + updatePriceDependentViews() } - var voting: Voting? { - switch self { - case let .preparing(model): - return model.voting - case let .deciding(model): - return model.voting - case .approved, - .rejected, - .cancelled, - .timedOut, - .killed, - .executed: - return nil - } + func didReceive(json: String?) { + view?.didReceive(json: json, jsonTitle: "Parameters JSON") } -} -extension Referenda.Curve { - // TODO: localize? - var displayName: String { - switch self { - case .linearDecreasing: - return "Linear Decreasing" - case .reciprocal: - return "Reciprocal" - case .steppedDecreasing: - return "Stepped Decreasing" - case .unknown: - return "Unknown" - } + func didReceive(error: ReferendumFullDetailsError) { + print("Received error: \(error.localizedDescription)") } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift index 4d35ea0b72..0c764d8363 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift @@ -1,6 +1,8 @@ protocol ReferendumFullDetailsViewProtocol: ControllerBackedProtocol { func didReceive(proposerModel: ProposerTableCell.Model?) func didReceive(json: String?, jsonTitle: String) + func didReceive(amountSpendDetails: AmountSpendDetailsTableView.Model?) + func didReceive(deposit: MultiValueView.Model, title: String) func didReceive( approveCurve: TitleWithSubtitleViewModel?, supportCurve: TitleWithSubtitleViewModel?, @@ -14,6 +16,7 @@ protocol ReferendumFullDetailsPresenterProtocol: AnyObject { protocol ReferendumFullDetailsInteractorOutputProtocol: AnyObject { func didReceive(price: PriceData?) + func didReceive(json: String?) func didReceive(error: ReferendumFullDetailsError) } @@ -25,4 +28,6 @@ protocol ReferendumFullDetailsInteractorInputProtocol: AnyObject { enum ReferendumFullDetailsError: Error { case priceFailed(Error) + case emptyJSON + case processingJSON(Error) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift index 15dab24b36..b942ac3877 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift @@ -45,11 +45,17 @@ extension ReferendumFullDetailsViewController: ReferendumFullDetailsViewProtocol supportCurve: TitleWithSubtitleViewModel?, callHash: TitleWithSubtitleViewModel? ) { - rootView.approveCurve.titleLabel.text = approveCurve?.title - rootView.approveCurve.detailsLabel.text = approveCurve?.subtitle - rootView.supportCurve.titleLabel.text = supportCurve?.title - rootView.supportCurve.detailsLabel.text = supportCurve?.subtitle - rootView.callHash.titleLabel.text = callHash?.title - rootView.callHash.detailsLabel.text = callHash?.subtitle + rootView.update(approveCurveModel: approveCurve) + rootView.update(supportCurveModel: supportCurve) + rootView.update(callHashModel: callHash) + } + + func didReceive(amountSpendDetails: AmountSpendDetailsTableView.Model?) { + rootView.update(amountSpendDetails: amountSpendDetails) + } + + func didReceive(deposit: MultiValueView.Model, title: String) { + rootView.depositTableCell.titleLabel.text = title + rootView.depositTableCell.rowContentView.valueView.bind(viewModel: deposit) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift index fb5baeae1c..8c5c34e044 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift @@ -8,13 +8,24 @@ struct ReferendumFullDetailsViewFactory { actionDetails: ReferendumActionLocal, identities: [AccountAddress: AccountIdentity] ) -> ReferendumFullDetailsViewProtocol? { - guard let chain = state.settings.value else { + guard let chain = state.settings.value, + let currencyManager = CurrencyManager.shared else { return nil } let wireframe = ReferendumFullDetailsWireframe() + let processingOperationFactory = PrettyPrintedJSONOperationFactory(preprocessor: ExtrinsicJSONProcessor()) + let interactor = ReferendumFullDetailsInteractor( + chain: chain, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + currencyManager: currencyManager, + processingOperationFactory: processingOperationFactory, + referendumAction: actionDetails, + operationQueue: OperationManagerFacade.sharedDefaultQueue + ) let presenter = ReferendumFullDetailsPresenter( + interactor: interactor, wireframe: wireframe, chainIconGenerator: PolkadotIconGenerator(), chain: chain, diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index 94b1e4a95b..df6ffa14cf 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -11,15 +11,16 @@ final class ReferendumFullDetailsViewLayout: UIView { let accountDetailsTableView = StackTableView() var referendumDetailsTableView = StackTableView() + var amountSpendDetailsTableView: AmountSpendDetailsTableView? + lazy var beneficiaryTableCell = StackInfoTableCell() + lazy var requestedAmountTableCell = StackTitleMultiValueCell() var proposerTableCell: StackInfoTableCell? let depositTableCell = StackTitleMultiValueCell() - let approveCurve = StackTableCell() - let supportCurve = StackTableCell() - let callHash: StackInfoTableCell = .create { - $0.detailsLabel.lineBreakMode = .byTruncatingMiddle - } + var approveCurve: StackTableCell? + var supportCurve: StackTableCell? + var callHash: StackInfoTableCell? let jsonTitle: UILabel = .init(style: .rowTitle) let jsonView: BlurredView = .create { @@ -44,11 +45,7 @@ final class ReferendumFullDetailsViewLayout: UIView { containerView.stackView.spacing = 8 containerView.stackView.addArrangedSubview(accountDetailsTableView) containerView.stackView.addArrangedSubview(referendumDetailsTableView) - accountDetailsTableView.addArrangedSubview(depositTableCell) - referendumDetailsTableView.addArrangedSubview(approveCurve) - referendumDetailsTableView.addArrangedSubview(supportCurve) - referendumDetailsTableView.addArrangedSubview(callHash) containerView.stackView.addArrangedSubview(jsonTitle) containerView.stackView.addArrangedSubview(jsonView) } @@ -68,6 +65,65 @@ final class ReferendumFullDetailsViewLayout: UIView { proposerTableCell?.bind(viewModel: proposerModel.model) } + func update(amountSpendDetails: AmountSpendDetailsTableView.Model?) { + guard let amountSpendDetails = amountSpendDetails else { + amountSpendDetailsTableView?.removeFromSuperview() + amountSpendDetailsTableView = nil + return + } + if amountSpendDetailsTableView == nil { + amountSpendDetailsTableView = .init() + accountDetailsTableView.addArrangedSubview(beneficiaryTableCell) + accountDetailsTableView.addArrangedSubview(requestedAmountTableCell) + } + beneficiaryTableCell.titleLabel.text = amountSpendDetails.beneficiary.title + beneficiaryTableCell.bind(viewModel: amountSpendDetails.beneficiary.model) + requestedAmountTableCell.titleLabel.text = amountSpendDetails.requestedAmount.title + requestedAmountTableCell.rowContentView.valueView.bind(viewModel: amountSpendDetails.requestedAmount.model) + } + + func update(approveCurveModel: TitleWithSubtitleViewModel?) { + guard let model = approveCurveModel else { + approveCurve?.removeFromSuperview() + approveCurve = nil + return + } + if approveCurve == nil { + approveCurve = .init() + approveCurve.map(referendumDetailsTableView.addArrangedSubview) + } + approveCurve?.titleLabel.text = model.title + approveCurve?.detailsLabel.text = model.subtitle + } + + func update(supportCurveModel: TitleWithSubtitleViewModel?) { + guard let model = supportCurveModel else { + supportCurve?.removeFromSuperview() + supportCurve = nil + return + } + if supportCurve == nil { + supportCurve = .init() + supportCurve.map(referendumDetailsTableView.addArrangedSubview) + } + supportCurve?.titleLabel.text = model.title + supportCurve?.detailsLabel.text = model.subtitle + } + + func update(callHashModel: TitleWithSubtitleViewModel?) { + guard let model = callHashModel else { + callHash?.removeFromSuperview() + callHash = nil + return + } + if callHash == nil { + callHash = .init() + callHash.map(referendumDetailsTableView.addArrangedSubview) + } + callHash?.titleLabel.text = model.title + callHash?.detailsLabel.text = model.subtitle + } + private func createStackInfoCell(title: String) -> StackInfoTableCell { let proposerCell = StackInfoTableCell() proposerCell.rowContentView.valueView.mode = .iconDetails @@ -85,7 +141,6 @@ extension ProposerTableCell { } typealias AmountSpendDetailsTableView = StackTableView - extension AmountSpendDetailsTableView { struct Model { let beneficiary: BeneficiaryModel @@ -99,56 +154,6 @@ extension AmountSpendDetailsTableView { struct RequestedAmountModel { let title: String - let model: StackCellViewModel? - } -} - -class BlurredView: UIView where TContentView: UIView { - let view: TContentView = .init() - let backgroundBlurView = TriangularedBlurView() - - var contentInsets: UIEdgeInsets = .init(top: 0, left: 16, bottom: 0, right: 16) { - didSet { - updateLayout() - } - } - - var innerInsets: UIEdgeInsets = .zero { - didSet { - updateLayout() - } - } - - override init(frame: CGRect) { - super.init(frame: frame) - - backgroundColor = .clear - setupLayout() - } - - @available(*, unavailable) - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupLayout() { - addSubview(backgroundBlurView) - backgroundBlurView.snp.makeConstraints { - $0.edges.equalToSuperview().inset(contentInsets) - } - - backgroundBlurView.addSubview(view) - view.snp.makeConstraints { - $0.edges.equalToSuperview().inset(innerInsets) - } - } - - private func updateLayout() { - backgroundBlurView.snp.updateConstraints { - $0.edges.equalToSuperview().inset(contentInsets) - } - view.snp.updateConstraints { - $0.edges.equalToSuperview().inset(innerInsets) - } + let model: MultiValueView.Model } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift new file mode 100644 index 0000000000..7df05ebb18 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift @@ -0,0 +1,62 @@ +extension ReferendumStateLocal { + var approvalCurve: Referenda.Curve? { + switch voting { + case let .supportAndVotes(model): + return model.approvalFunction?.curve + case .none: + return nil + } + } + + var supportCurve: Referenda.Curve? { + switch voting { + case let .supportAndVotes(model): + return model.supportFunction?.curve + case .none: + return nil + } + } + + var callHash: String? { + switch proposal { + case let .lookup(lookup): + return String(data: lookup.hash, encoding: .utf8) + case let .legacy(hash): + return String(data: hash, encoding: .utf8) + case .inline, .unknown, .none: + return nil + } + } + + var voting: Voting? { + switch self { + case let .preparing(model): + return model.voting + case let .deciding(model): + return model.voting + case .approved, + .rejected, + .cancelled, + .timedOut, + .killed, + .executed: + return nil + } + } +} + +extension Referenda.Curve { + // TODO: localize? + var displayName: String { + switch self { + case .linearDecreasing: + return "Linear Decreasing" + case .reciprocal: + return "Reciprocal" + case .steppedDecreasing: + return "Stepped Decreasing" + case .unknown: + return "Unknown" + } + } +} From 6a928a07811829727105d1f6976d480ce0161a94 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 22 Oct 2022 11:54:07 +0500 Subject: [PATCH 084/229] add confirmation logic --- novawallet.xcodeproj/project.pbxproj | 12 + novawallet/Common/Model/AssetBalance.swift | 4 + .../ConvictionVoting/ConvictionVoting.swift | 2 + .../Common/View/StackTitleValueDiffCell.swift | 2 + .../ReferendumVoteInteractor.swift | 7 + .../Model/ReferendumVoteConfirmError.swift | 6 + .../ReferendumVoteConfirmInteractor.swift | 63 +++- .../ReferendumVoteConfirmPresenter.swift | 351 +++++++++++++++++- .../ReferendumVoteConfirmProtocols.swift | 26 +- .../ReferendumVoteConfirmViewController.swift | 127 ++++++- .../ReferendumVoteConfirmViewFactory.swift | 39 +- .../ReferendumVoteConfirmWireframe.swift | 13 +- .../ReferendumVoteSetupViewController.swift | 2 + .../ReferendumVoteSetupViewFactory.swift | 8 +- .../ReferendumVoteSetupViewLayout.swift | 2 + ...ReferendumLockChangeViewModelFactory.swift | 70 +++- novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 18 files changed, 719 insertions(+), 17 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/Model/ReferendumVoteConfirmError.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 065702eecf..a9539ed5d6 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -934,6 +934,7 @@ 8459A9CC2746A1E9000D6278 /* CrowdloanOffchainSubscriptionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8459A9CB2746A1E9000D6278 /* CrowdloanOffchainSubscriptionHandler.swift */; }; 845AADA12902D02400B5AE96 /* TitleValueDiffView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845AADA02902D02400B5AE96 /* TitleValueDiffView.swift */; }; 845AADA32902D1EB00B5AE96 /* StackTitleValueDiffCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845AADA22902D1EA00B5AE96 /* StackTitleValueDiffCell.swift */; }; + 845AADA62903B32E00B5AE96 /* ReferendumVoteConfirmError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845AADA52903B32E00B5AE96 /* ReferendumVoteConfirmError.swift */; }; 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811128F429BB0040CE84 /* SupportPallet.swift */; }; 845B811528F43C350040CE84 /* Treasury.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811428F43C350040CE84 /* Treasury.swift */; }; 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811628F43C730040CE84 /* TreasuryProposal.swift */; }; @@ -3840,6 +3841,7 @@ 8459A9CB2746A1E9000D6278 /* CrowdloanOffchainSubscriptionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanOffchainSubscriptionHandler.swift; sourceTree = ""; }; 845AADA02902D02400B5AE96 /* TitleValueDiffView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleValueDiffView.swift; sourceTree = ""; }; 845AADA22902D1EA00B5AE96 /* StackTitleValueDiffCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackTitleValueDiffCell.swift; sourceTree = ""; }; + 845AADA52903B32E00B5AE96 /* ReferendumVoteConfirmError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmError.swift; sourceTree = ""; }; 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; @@ -7935,6 +7937,14 @@ path = EntityToModel; sourceTree = ""; }; + 845AADA42903B30400B5AE96 /* Model */ = { + isa = PBXGroup; + children = ( + 845AADA52903B32E00B5AE96 /* ReferendumVoteConfirmError.swift */, + ); + path = Model; + sourceTree = ""; + }; 845B811028F429AB0040CE84 /* Support */ = { isa = PBXGroup; children = ( @@ -12927,6 +12937,7 @@ B320B465EE16F566DDFE5D8C /* ReferendumVoteConfirm */ = { isa = PBXGroup; children = ( + 845AADA42903B30400B5AE96 /* Model */, DE767858B6CF5F6F7C7B418E /* ReferendumVoteConfirmProtocols.swift */, 3C784EDFB9227884E30FBE6E /* ReferendumVoteConfirmWireframe.swift */, CDB47990BC7A594E663DAC00 /* ReferendumVoteConfirmPresenter.swift */, @@ -16514,6 +16525,7 @@ DE03CA5AD7F1D0B80DFF13B6 /* DAppBrowserViewController.swift in Sources */, 8442002328E6FE1E00C49C4A /* ReferendumsViewManager.swift in Sources */, 70C0E48EE41B4C7229F5946C /* DAppBrowserViewLayout.swift in Sources */, + 845AADA62903B32E00B5AE96 /* ReferendumVoteConfirmError.swift in Sources */, FDE2CA45061C620567AC329C /* DAppBrowserViewFactory.swift in Sources */, 882C29AC28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift in Sources */, 84BC7045289EFF44008A9758 /* TransactionDisplayCode.swift in Sources */, diff --git a/novawallet/Common/Model/AssetBalance.swift b/novawallet/Common/Model/AssetBalance.swift index 6e3171623f..f768e55805 100644 --- a/novawallet/Common/Model/AssetBalance.swift +++ b/novawallet/Common/Model/AssetBalance.swift @@ -12,6 +12,10 @@ struct AssetBalance: Equatable { var totalInPlank: BigUInt { freeInPlank + reservedInPlank } var transferable: BigUInt { freeInPlank > frozenInPlank ? freeInPlank - frozenInPlank : 0 } var locked: BigUInt { frozenInPlank + reservedInPlank } + + func newTransferable(for frozen: BigUInt) -> BigUInt { + freeInPlank > frozen ? freeInPlank - frozen : 0 + } } extension AssetBalance: Identifiable { diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index bc36cd8dfc..f5829f8454 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -5,6 +5,8 @@ import BigInt enum ConvictionVoting { typealias PollIndex = UInt32 + static var lockId: String = "pyconvot" + enum Conviction: UInt8, Decodable { /// 0.1x votes, unlocked. case none diff --git a/novawallet/Common/View/StackTitleValueDiffCell.swift b/novawallet/Common/View/StackTitleValueDiffCell.swift index c901f84bd9..0a81c2df1c 100644 --- a/novawallet/Common/View/StackTitleValueDiffCell.swift +++ b/novawallet/Common/View/StackTitleValueDiffCell.swift @@ -12,6 +12,8 @@ final class StackTitleValueDiffCell: RowView, StackTableView } private func configureStyle() { + rowContentView.applyDefaultStyle() + preferredHeight = 44.0 borderView.strokeColor = R.color.colorWhite8()! diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift index 28ad88d677..d0022f6c6e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift @@ -194,6 +194,13 @@ class ReferendumVoteInteractor: AnyCancellableCleaning { func remakeSubscriptions() { makeSubscriptions() } + + func handleAccountLocks( + result _: Result<[DataProviderChange], Error>, + accountId _: AccountId, + chainId _: ChainModel.Id, + assetId _: AssetModel.Id + ) {} } extension ReferendumVoteInteractor: ReferendumVoteInteractorInputProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/Model/ReferendumVoteConfirmError.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/Model/ReferendumVoteConfirmError.swift new file mode 100644 index 0000000000..5e6b750d28 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/Model/ReferendumVoteConfirmError.swift @@ -0,0 +1,6 @@ +import Foundation + +enum ReferendumVoteConfirmError: Error { + case locksSubscriptionFailed(_ internalError: Error) + case submitVoteFailed(_ internalError: Error) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift index 2a708937b3..6a09626623 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift @@ -1,11 +1,22 @@ import UIKit import SubstrateSdk +import RobinHood final class ReferendumVoteConfirmInteractor: ReferendumVoteInteractor { - weak var presenter: ReferendumVoteConfirmInteractorOutputProtocol? + var presenter: ReferendumVoteConfirmInteractorOutputProtocol? { + get { + basePresenter as? ReferendumVoteConfirmInteractorOutputProtocol + } + + set { + basePresenter = newValue + } + } let signer: SigningWrapperProtocol + private var locksSubscription: StreamableProvider? + init( referendumIndex: ReferendumIdLocal, selectedAccount: MetaChainAccountResponse, @@ -46,6 +57,48 @@ final class ReferendumVoteConfirmInteractor: ReferendumVoteInteractor { operationQueue: operationQueue ) } + + private func clearAndSubscribeLocks() { + locksSubscription?.removeObserver(self) + locksSubscription = nil + + guard let asset = chain.utilityAsset() else { + return + } + + locksSubscription = subscribeToLocksProvider( + for: selectedAccount.chainAccount.accountId, + chainId: chain.chainId, + assetId: asset.assetId + ) + } + + override func setup() { + super.setup() + + clearAndSubscribeLocks() + } + + override func remakeSubscriptions() { + super.remakeSubscriptions() + + clearAndSubscribeLocks() + } + + override func handleAccountLocks( + result: Result<[DataProviderChange], Error>, + accountId _: AccountId, + chainId _: ChainModel.Id, + assetId _: AssetModel.Id + ) { + switch result { + case let .success(changes): + let locks = changes.mergeToDict([:]).values + presenter?.didReceiveLocks(Array(locks)) + case let .failure(error): + presenter?.didReceiveError(.locksSubscriptionFailed(error)) + } + } } extension ReferendumVoteConfirmInteractor: ReferendumVoteConfirmInteractorInputProtocol { @@ -62,7 +115,13 @@ extension ReferendumVoteConfirmInteractor: ReferendumVoteConfirmInteractorInputP ) } - extrinsicService.submit(closure, signer: signer, runningIn: .main) { [weak self] _ in + extrinsicService.submit(closure, signer: signer, runningIn: .main) { [weak self] result in + switch result { + case let .success(hash): + self?.presenter?.didReceiveVotingHash(hash) + case let .failure(error): + self?.presenter?.didReceiveError(.submitVoteFailed(error)) + } } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift index 16bcbd316b..8d607947d5 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift @@ -1,21 +1,366 @@ import Foundation +import BigInt +import SoraFoundation final class ReferendumVoteConfirmPresenter { weak var view: ReferendumVoteConfirmViewProtocol? let wireframe: ReferendumVoteConfirmWireframeProtocol let interactor: ReferendumVoteConfirmInteractorInputProtocol + let chain: ChainModel + let selectedAccount: MetaChainAccountResponse + let vote: ReferendumNewVote + + let balanceViewModelFactory: BalanceViewModelFactoryProtocol + let referendumFormatter: LocalizableResource + let referendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol + let lockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol + let logger: LoggerProtocol + + private var assetBalance: AssetBalance? + private var fee: BigUInt? + private var priceData: PriceData? + private var votesResult: CallbackStorageSubscriptionResult? + private var blockNumber: BlockNumber? + private var blockTime: BlockTime? + private var referendum: ReferendumLocal? + private var lockDiff: GovernanceLockStateDiff? + private var assetLocks: AssetLocks? + + private lazy var walletDisplayViewModelFactory = WalletAccountViewModelFactory() + private lazy var addressDisplayViewModelFactory = DisplayAddressViewModelFactory() + init( + vote: ReferendumNewVote, + chain: ChainModel, + selectedAccount: MetaChainAccountResponse, + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + referendumFormatter: LocalizableResource, + referendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol, + lockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol, interactor: ReferendumVoteConfirmInteractorInputProtocol, - wireframe: ReferendumVoteConfirmWireframeProtocol + wireframe: ReferendumVoteConfirmWireframeProtocol, + localizationManager: LocalizationManagerProtocol, + logger: LoggerProtocol ) { + self.vote = vote + self.chain = chain + self.selectedAccount = selectedAccount + self.balanceViewModelFactory = balanceViewModelFactory + self.referendumFormatter = referendumFormatter + self.referendumStringsViewModelFactory = referendumStringsViewModelFactory + self.lockChangeViewModelFactory = lockChangeViewModelFactory self.interactor = interactor self.wireframe = wireframe + self.logger = logger + self.localizationManager = localizationManager + } + + private func provideReferendumIndex() { + let referendumString = referendumFormatter.value(for: selectedLocale).string(from: vote.index as NSNumber) + view?.didReceive(referendumNumber: referendumString ?? "") + } + + private func provideAmountViewModel() { + guard + let precision = chain.utilityAsset()?.displayInfo.assetPrecision, + let decimalAmount = Decimal.fromSubstrateAmount( + vote.voteAction.amount, + precision: precision + ) else { + return + } + + let viewModel = balanceViewModelFactory.spendingAmountFromPrice( + decimalAmount, + priceData: priceData + ).value(for: selectedLocale) + + view?.didReceiveAmount(viewModel: viewModel) + } + + private func provideWalletViewModel() { + guard let viewModel = try? walletDisplayViewModelFactory.createDisplayViewModel(from: selectedAccount) else { + return + } + + view?.didReceiveWallet(viewModel: viewModel.cellViewModel) + } + + private func provideAccountViewModel() { + guard let address = selectedAccount.chainAccount.toAddress() else { + return + } + + let viewModel = addressDisplayViewModelFactory.createViewModel(from: address) + view?.didReceiveAccount(viewModel: viewModel) + } + + private func provideFeeViewModel() { + if let fee = fee { + guard let precision = chain.utilityAsset()?.displayInfo.assetPrecision else { + return + } + + let feeDecimal = Decimal.fromSubstrateAmount( + fee, + precision: precision + ) ?? 0.0 + + let viewModel = balanceViewModelFactory.balanceFromPrice(feeDecimal, priceData: priceData) + .value(for: selectedLocale) + + view?.didReceiveFee(viewModel: viewModel) + } else { + view?.didReceiveFee(viewModel: nil) + } + } + + private func provideYourVoteViewModel() { + let votesString = referendumStringsViewModelFactory.createVotes( + from: vote.voteAction.conviction.votes(for: vote.voteAction.amount) ?? 0, + chain: chain, + locale: selectedLocale + ) + + let convictionString = referendumStringsViewModelFactory.createVotesDetails( + from: vote.voteAction.amount, + conviction: vote.voteAction.conviction.decimalValue, + chain: chain, + locale: selectedLocale + ) + + let voteSide: String + + if vote.voteAction.isAye { + voteSide = R.string.localizable.governanceAye(preferredLanguages: selectedLocale.rLanguages) + } else { + voteSide = R.string.localizable.governanceNay(preferredLanguages: selectedLocale.rLanguages) + } + + let title = R.string.localizable.govYourVote(preferredLanguages: selectedLocale.rLanguages) + + let viewModel = YourVoteRow.Model( + vote: .init(title: title, description: voteSide), + amount: .init(topValue: votesString ?? "", bottomValue: convictionString) + ) + + view?.didReceiveYourVote(viewModel: viewModel) + } + + private func provideTransferableAmountViewModel() { + guard + let assetBalance = assetBalance, + let assetLocks = assetLocks, + let lockDiff = lockDiff, + let viewModel = lockChangeViewModelFactory.createTransferableAmountViewModel( + from: lockDiff, + balance: assetBalance, + locks: assetLocks, + locale: selectedLocale + ) else { + return + } + + view?.didReceiveTransferableAmount(viewModel: viewModel) + } + + private func provideLockedAmountViewModel() { + guard + let lockDiff = lockDiff, + let viewModel = lockChangeViewModelFactory.createAmountViewModel( + from: lockDiff, + locale: selectedLocale + ) else { + return + } + + view?.didReceiveLockedAmount(viewModel: viewModel) + } + + private func provideLockedPeriodViewModel() { + guard + let lockDiff = lockDiff, + let blockNumber = blockNumber, + let blockTime = blockTime, + let viewModel = lockChangeViewModelFactory.createPeriodViewModel( + from: lockDiff, + blockNumber: blockNumber, + blockTime: blockTime, + locale: selectedLocale + ) else { + return + } + + view?.didReceiveLockedPeriod(viewModel: viewModel) + } + + private func refreshFee() { + interactor.estimateFee(for: vote.voteAction) + } + + private func refreshLockDiff() { + interactor.refreshLockDiff( + for: votesResult?.value?.votes.votes ?? [:], + newVote: vote, + blockHash: votesResult?.blockHash + ) + } + + private func updateView() { + provideReferendumIndex() + provideAmountViewModel() + provideWalletViewModel() + provideAccountViewModel() + provideFeeViewModel() + provideYourVoteViewModel() + provideTransferableAmountViewModel() + provideLockedAmountViewModel() + provideLockedPeriodViewModel() } } extension ReferendumVoteConfirmPresenter: ReferendumVoteConfirmPresenterProtocol { - func setup() {} + func setup() { + updateView() + + interactor.setup() + + refreshFee() + } + + func confirm() { + view?.didStartLoading() + + interactor.submit(vote: vote.voteAction) + } + + func presentSenderDetails() { + guard + let address = try? selectedAccount.chainAccount.accountId.toAddress(using: chain.chainFormat), + let view = view else { + return + } + + wireframe.presentAccountOptions( + from: view, + address: address, + chain: chain, + locale: selectedLocale + ) + } +} + +extension ReferendumVoteConfirmPresenter: ReferendumVoteConfirmInteractorOutputProtocol { + func didReceiveAssetBalance(_ assetBalance: AssetBalance?) { + self.assetBalance = assetBalance + } + + func didReceivePrice(_ priceData: PriceData?) { + self.priceData = priceData + + provideAmountViewModel() + provideFeeViewModel() + } + + func didReceiveVotingReferendum(_ referendum: ReferendumLocal) { + self.referendum = referendum + } + + func didReceiveFee(_ fee: BigUInt) { + self.fee = fee + + provideFeeViewModel() + } + + func didReceiveLockStateDiff(_ diff: GovernanceLockStateDiff) { + lockDiff = diff + + provideTransferableAmountViewModel() + provideLockedAmountViewModel() + provideLockedPeriodViewModel() + } + + func didReceiveAccountVotes(_ votes: CallbackStorageSubscriptionResult) { + votesResult = votes + + refreshLockDiff() + } + + func didReceiveBlockNumber(_ blockNumber: BlockNumber) { + self.blockNumber = blockNumber + + interactor.refreshBlockTime() + + provideLockedPeriodViewModel() + } + + func didReceiveBlockTime(_ blockTime: BlockTime) { + self.blockTime = blockTime + + provideLockedPeriodViewModel() + } + + func didReceiveLocks(_ locks: AssetLocks) { + assetLocks = locks + + provideTransferableAmountViewModel() + } + + func didReceiveBaseError(_ error: ReferendumVoteInteractorError) { + logger.error("Did receive base error: \(error)") + + switch error { + case .assetBalanceFailed, .priceFailed, .votingReferendumFailed, .accountVotesFailed, + .blockNumberSubscriptionFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + case .feeFailed: + wireframe.presentFeeStatus(on: view, locale: selectedLocale) { [weak self] in + self?.refreshFee() + } + case .blockTimeFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refreshBlockTime() + } + case .stateDiffFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.refreshLockDiff() + } + } + } + + func didReceiveVotingHash(_: String) { + view?.didStopLoading() + + wireframe.presentExtrinsicSubmission(from: view, completionAction: .dismiss, locale: selectedLocale) + } + + func didReceiveError(_ error: ReferendumVoteConfirmError) { + logger.error("Did receive error: \(error)") + + switch error { + case .locksSubscriptionFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + case let .submitVoteFailed(internalError): + view?.didStopLoading() + + if internalError.isWatchOnlySigning { + wireframe.presentDismissingNoSigningView(from: view) + } else { + _ = wireframe.present(error: internalError, from: view, locale: selectedLocale) + } + } + } } -extension ReferendumVoteConfirmPresenter: ReferendumVoteConfirmInteractorOutputProtocol {} +extension ReferendumVoteConfirmPresenter: Localizable { + func applyLocalization() { + if let view = view, view.isSetup { + updateView() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift index 4ba9e1bd9e..e4a3078831 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift @@ -1,13 +1,33 @@ -protocol ReferendumVoteConfirmViewProtocol: ControllerBackedProtocol {} +import Foundation + +protocol ReferendumVoteConfirmViewProtocol: ControllerBackedProtocol, LoadableViewProtocol { + func didReceive(referendumNumber: String) + func didReceiveAmount(viewModel: BalanceViewModelProtocol) + func didReceiveWallet(viewModel: StackCellViewModel) + func didReceiveAccount(viewModel: DisplayAddressViewModel) + func didReceiveFee(viewModel: BalanceViewModelProtocol?) + func didReceiveYourVote(viewModel: YourVoteRow.Model) + func didReceiveTransferableAmount(viewModel: ReferendumLockTransitionViewModel) + func didReceiveLockedAmount(viewModel: ReferendumLockTransitionViewModel) + func didReceiveLockedPeriod(viewModel: ReferendumLockTransitionViewModel) +} protocol ReferendumVoteConfirmPresenterProtocol: AnyObject { func setup() + func confirm() + func presentSenderDetails() } protocol ReferendumVoteConfirmInteractorInputProtocol: ReferendumVoteInteractorInputProtocol { func submit(vote: ReferendumVoteAction) } -protocol ReferendumVoteConfirmInteractorOutputProtocol: AnyObject {} +protocol ReferendumVoteConfirmInteractorOutputProtocol: ReferendumVoteInteractorOutputProtocol { + func didReceiveLocks(_ locks: AssetLocks) + func didReceiveVotingHash(_ hash: String) + func didReceiveError(_ error: ReferendumVoteConfirmError) +} -protocol ReferendumVoteConfirmWireframeProtocol: AnyObject {} +protocol ReferendumVoteConfirmWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, FeeRetryable, + MessageSheetPresentable, AddressOptionsPresentable, + ExtrinsicSubmissionPresenting {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift index 17442e0bd4..da7a62db16 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift @@ -1,13 +1,18 @@ import UIKit +import SoraFoundation -final class ReferendumVoteConfirmViewController: UIViewController { +final class ReferendumVoteConfirmViewController: UIViewController, ViewHolder { typealias RootViewType = ReferendumVoteConfirmViewLayout let presenter: ReferendumVoteConfirmPresenterProtocol - init(presenter: ReferendumVoteConfirmPresenterProtocol) { + private var referendumNumber: String? + + init(presenter: ReferendumVoteConfirmPresenterProtocol, localizationManager: LocalizationManagerProtocol) { self.presenter = presenter super.init(nibName: nil, bundle: nil) + + self.localizationManager = localizationManager } @available(*, unavailable) @@ -22,8 +27,124 @@ final class ReferendumVoteConfirmViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + setupHandlers() + setupLocalization() + presenter.setup() } + + private func setupHandlers() { + rootView.actionLoadableView.actionButton.addTarget( + self, + action: #selector(actionConfirm), + for: .touchUpInside + ) + + rootView.accountCell.addTarget( + self, + action: #selector(actionSender), + for: .touchUpInside + ) + } + + private func setupLocalization() { + let languages = selectedLocale.rLanguages + + applyReferendumNumber() + + rootView.walletCell.titleLabel.text = R.string.localizable.commonWallet(preferredLanguages: languages) + rootView.accountCell.titleLabel.text = R.string.localizable.commonSender(preferredLanguages: languages) + + rootView.feeCell.rowContentView.locale = selectedLocale + + rootView.transferableTitleLabel.text = R.string.localizable.walletBalanceAvailable( + preferredLanguages: languages + ) + + rootView.lockAmountTitleLabel.text = R.string.localizable.commonGovLock(preferredLanguages: languages) + rootView.lockPeriodTitleLabel.text = R.string.localizable.commonLockingPeriod(preferredLanguages: languages) + + let hint = R.string.localizable.govVoteSetupHint(preferredLanguages: languages) + rootView.hintsView.bind(texts: [hint]) + + rootView.actionLoadableView.actionButton.imageWithTitleView?.title = R.string.localizable + .commonConfirm(preferredLanguages: selectedLocale.rLanguages) + } + + private func applyReferendumNumber() { + let languages = selectedLocale.rLanguages + + title = R.string.localizable.govVoteSetupTitleFormat( + referendumNumber ?? "", + preferredLanguages: languages + ) + } + + @objc private func actionConfirm() { + presenter.confirm() + } + + @objc private func actionSender() { + presenter.presentSenderDetails() + } +} + +extension ReferendumVoteConfirmViewController: ReferendumVoteConfirmViewProtocol { + func didReceive(referendumNumber: String) { + self.referendumNumber = referendumNumber + + applyReferendumNumber() + } + + func didReceiveAmount(viewModel: BalanceViewModelProtocol) { + rootView.amountView.bind(viewModel: viewModel) + } + + func didReceiveWallet(viewModel: StackCellViewModel) { + rootView.walletCell.bind(viewModel: viewModel) + } + + func didReceiveAccount(viewModel: DisplayAddressViewModel) { + rootView.accountCell.bind(viewModel: viewModel.cellViewModel) + } + + func didReceiveFee(viewModel: BalanceViewModelProtocol?) { + rootView.feeCell.rowContentView.bind(viewModel: viewModel) + } + + func didReceiveYourVote(viewModel: YourVoteRow.Model) { + rootView.yourVoteView.bind(viewModel: viewModel) + } + + func didReceiveTransferableAmount(viewModel: ReferendumLockTransitionViewModel) { + rootView.transferableCell.bind(viewModel: viewModel) + } + + func didReceiveLockedAmount(viewModel: ReferendumLockTransitionViewModel) { + rootView.lockedAmountCell.bind(viewModel: viewModel) + } + + func didReceiveLockedPeriod(viewModel: ReferendumLockTransitionViewModel) { + rootView.lockedPeriodCell.bind(viewModel: viewModel) + } +} + +extension ReferendumVoteConfirmViewController: LoadableViewProtocol { + func didStartLoading() { + rootView.actionLoadableView.startLoading() + } + + func didStopLoading() { + rootView.actionLoadableView.stopLoading() + } +} + +extension ReferendumVoteConfirmViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + setupLocalization() + } + } } -extension ReferendumVoteConfirmViewController: ReferendumVoteConfirmViewProtocol {} +extension ReferendumVoteConfirmViewController: ImportantViewProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift index 2c90f8cbb2..b1ca9f88a9 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -1,6 +1,7 @@ import Foundation import RobinHood import SubstrateSdk +import SoraFoundation struct ReferendumVoteConfirmViewFactory { static func createView( @@ -13,15 +14,49 @@ struct ReferendumVoteConfirmViewFactory { for: state, referendum: newVote.index, currencyManager: currencyManager + ), + let chain = state.settings.value, + let assetDisplayInfo = chain.utilityAsset()?.displayInfo(with: chain.icon), + let selectedAccount = SelectedWalletSettings.shared.value?.fetchMetaChainAccount( + for: chain.accountRequest() ) else { return nil } let wireframe = ReferendumVoteConfirmWireframe() - let presenter = ReferendumVoteConfirmPresenter(interactor: interactor, wireframe: wireframe) + let localizationManager = LocalizationManager.shared + + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: assetDisplayInfo, + priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) + ) + + let lockChangeViewModelFactory = ReferendumLockChangeViewModelFactory( + assetDisplayInfo: assetDisplayInfo, + votingLockId: ConvictionVoting.lockId + ) + + let referendumStringsViewModelFactory = ReferendumDisplayStringFactory() - let view = ReferendumVoteConfirmViewController(presenter: presenter) + let presenter = ReferendumVoteConfirmPresenter( + vote: newVote, + chain: chain, + selectedAccount: selectedAccount, + balanceViewModelFactory: balanceViewModelFactory, + referendumFormatter: NumberFormatter.index.localizableResource(), + referendumStringsViewModelFactory: referendumStringsViewModelFactory, + lockChangeViewModelFactory: lockChangeViewModelFactory, + interactor: interactor, + wireframe: wireframe, + localizationManager: localizationManager, + logger: Logger.shared + ) + + let view = ReferendumVoteConfirmViewController( + presenter: presenter, + localizationManager: localizationManager + ) presenter.view = view interactor.presenter = presenter diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift index ac03e31278..cd1802af30 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift @@ -1,3 +1,14 @@ import Foundation -final class ReferendumVoteConfirmWireframe: ReferendumVoteConfirmWireframeProtocol {} +final class ReferendumVoteConfirmWireframe: ReferendumVoteConfirmWireframeProtocol, ModalAlertPresenting { + func complete(on view: ReferendumVoteConfirmViewProtocol?, locale: Locale) { + let title = R.string.localizable + .commonTransactionSubmitted(preferredLanguages: locale.rLanguages) + + let presenter = view?.controller.navigationController?.presentingViewController + + presenter?.dismiss(animated: true) { [weak self] in + self?.presentSuccessNotification(title, from: presenter, completion: nil) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift index 378d1fe0cc..581d83dd7d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -186,3 +186,5 @@ extension ReferendumVoteSetupViewController: Localizable { } } } + +extension ReferendumVoteSetupViewController: ImportantViewProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index 93b1b62624..4e66c39450 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -20,7 +20,7 @@ struct ReferendumVoteSetupViewFactory { return nil } - let wireframe = ReferendumVoteSetupWireframe() + let wireframe = ReferendumVoteSetupWireframe(state: state) let localizationManager = LocalizationManager.shared @@ -32,7 +32,11 @@ struct ReferendumVoteSetupViewFactory { let networkViewModelFactory = NetworkViewModelFactory() let chainAssetViewModelFactory = ChainAssetViewModelFactory(networkViewModelFactory: networkViewModelFactory) - let lockChangeViewModelFactory = ReferendumLockChangeViewModelFactory(assetDisplayInfo: assetDisplayInfo) + let lockChangeViewModelFactory = ReferendumLockChangeViewModelFactory( + assetDisplayInfo: assetDisplayInfo, + votingLockId: ConvictionVoting.lockId + ) + let referendumStringsViewModelFactory = ReferendumDisplayStringFactory() let presenter = ReferendumVoteSetupPresenter( diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index 42c17a34a7..3247ca25a2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -40,6 +40,7 @@ final class ReferendumVoteSetupViewLayout: UIView { } let lockedAmountView: TitleValueDiffView = .create { view in + view.applyDefaultStyle() view.titleView.imageView.image = R.image.iconGovAmountLock() } @@ -48,6 +49,7 @@ final class ReferendumVoteSetupViewLayout: UIView { } let lockedPeriodView: TitleValueDiffView = .create { view in + view.applyDefaultStyle() view.titleView.imageView.image = R.image.iconGovPeriodLock() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift index cce0882898..680274893d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift @@ -2,6 +2,13 @@ import Foundation import SoraFoundation protocol ReferendumLockChangeViewModelFactoryProtocol { + func createTransferableAmountViewModel( + from diff: GovernanceLockStateDiff, + balance: AssetBalance, + locks: AssetLocks, + locale: Locale + ) -> ReferendumLockTransitionViewModel? + func createAmountViewModel( from diff: GovernanceLockStateDiff, locale: Locale @@ -19,18 +26,79 @@ final class ReferendumLockChangeViewModelFactory { let balanceFormatter: LocalizableResource let amountFormatter: LocalizableResource let assetDisplayInfo: AssetBalanceDisplayInfo + let votingLockId: String init( assetDisplayInfo: AssetBalanceDisplayInfo, - assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol = AssetBalanceFormatterFactory() + assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol = AssetBalanceFormatterFactory(), + votingLockId: String ) { balanceFormatter = assetBalanceFormatterFactory.createTokenFormatter(for: assetDisplayInfo) amountFormatter = assetBalanceFormatterFactory.createDisplayFormatter(for: assetDisplayInfo) self.assetDisplayInfo = assetDisplayInfo + self.votingLockId = votingLockId } } extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol { + func createTransferableAmountViewModel( + from diff: GovernanceLockStateDiff, + balance: AssetBalance, + locks: AssetLocks, + locale: Locale + ) -> ReferendumLockTransitionViewModel? { + guard + let fromAmountDecimal = Decimal.fromSubstrateAmount( + balance.transferable, + precision: assetDisplayInfo.assetPrecision + ), + let fromAmountString = amountFormatter.value(for: locale).stringFromDecimal(fromAmountDecimal) else { + return nil + } + + let toAmountString: String + let change: ReferendumLockTransitionViewModel.Change? + + let balanceFormatter = balanceFormatter.value(for: locale) + + if let toState = diff.after { + let otherLocks = locks + .filter { $0.identifier != votingLockId } + .map(\.amount) + .max() ?? 0 + + let newLocked = max(otherLocks, toState.maxLockedAmount) + + let newTransferable = balance.newTransferable(for: newLocked) + + guard + let toAmountDecimal = Decimal.fromSubstrateAmount( + newTransferable, + precision: assetDisplayInfo.assetPrecision + ) else { + return nil + } + + toAmountString = balanceFormatter.stringFromDecimal(toAmountDecimal) ?? "" + + if toAmountDecimal > fromAmountDecimal { + let changeAmountString = balanceFormatter.stringFromDecimal(toAmountDecimal - fromAmountDecimal) ?? "" + change = .init(isIncrease: true, value: changeAmountString) + } else if toAmountDecimal < fromAmountDecimal { + let changeAmountString = balanceFormatter.stringFromDecimal(fromAmountDecimal - toAmountDecimal) ?? "" + change = .init(isIncrease: false, value: changeAmountString) + } else { + change = nil + } + + } else { + toAmountString = balanceFormatter.stringFromDecimal(fromAmountDecimal) ?? "" + change = nil + } + + return .init(fromValue: fromAmountString, toValue: toAmountString, change: change) + } + func createAmountViewModel( from diff: GovernanceLockStateDiff, locale: Locale diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 46f9a384c3..82fd6e6724 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1035,3 +1035,4 @@ "common.maximum" = "%@ maximum"; "gov.referendum.details.dApps.title" = "Use Nova DApp browser"; "gov.referendum.details.timeline.title" = "Timeline"; +"gov.your.vote" = "Your vote"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index c8ba349bdd..79728a0715 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1036,3 +1036,4 @@ "common.maximum" = "%@ максимум"; "gov.referendum.details.dApps.title" = "Использовать Nova DApp браузер"; "gov.referendum.details.timeline.title" = "Статусы"; +"gov.your.vote" = "Ваш голос"; From e0fe9fc92ba884bb551fb27c2aa585b985995452 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 23 Oct 2022 00:41:05 +0500 Subject: [PATCH 085/229] add voting validations --- novawallet.xcodeproj/project.pbxproj | 16 ++ .../ConvictionVoting+ConstantPath.swift | 4 + .../Governance/Model/ReferendumLocal.swift | 20 ++ .../Model/ReferendumVotingLocal.swift | 27 ++- .../Operation/Gov2OperationFactory.swift | 29 ++- .../GovernanceErrorPresentable.swift | 77 ++++++ .../GovernanceValidatorFactory.swift | 223 ++++++++++++++++++ novawallet/en.lproj/Localizable.strings | 8 + novawallet/ru.lproj/Localizable.strings | 8 + 9 files changed, 407 insertions(+), 5 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift create mode 100644 novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index a9539ed5d6..c177256c3f 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1840,6 +1840,8 @@ 84CEAAF526D7ADF20021B881 /* KeystoreMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEAAF426D7ADF20021B881 /* KeystoreMigrator.swift */; }; 84CEAAF726D7B8010021B881 /* SettingsMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEAAF626D7B8010021B881 /* SettingsMigrator.swift */; }; 84CEEDE2284E3DCE0039364A /* AccountDetailsNavigationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEEDE1284E3DCE0039364A /* AccountDetailsNavigationCell.swift */; }; + 84CEF288290462C300BA25BB /* GovernanceValidatorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEF287290462C300BA25BB /* GovernanceValidatorFactory.swift */; }; + 84CEF28A290466A800BA25BB /* GovernanceErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEF289290466A800BA25BB /* GovernanceErrorPresentable.swift */; }; 84CF00C327F6C1E4004DB322 /* CustomAssetMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CF00C227F6C1E4004DB322 /* CustomAssetMapper.swift */; }; 84CFBC6528756CCB00E93EDA /* EthereumError+Presentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CFBC6428756CCB00E93EDA /* EthereumError+Presentable.swift */; }; 84CFF1E326526FBC00DB7CF7 /* StakingBondMoreProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CFF1CF26526FBC00DB7CF7 /* StakingBondMoreProtocols.swift */; }; @@ -4754,6 +4756,8 @@ 84CEAAF426D7ADF20021B881 /* KeystoreMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeystoreMigrator.swift; sourceTree = ""; }; 84CEAAF626D7B8010021B881 /* SettingsMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsMigrator.swift; sourceTree = ""; }; 84CEEDE1284E3DCE0039364A /* AccountDetailsNavigationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDetailsNavigationCell.swift; sourceTree = ""; }; + 84CEF287290462C300BA25BB /* GovernanceValidatorFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceValidatorFactory.swift; sourceTree = ""; }; + 84CEF289290466A800BA25BB /* GovernanceErrorPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceErrorPresentable.swift; sourceTree = ""; }; 84CF00C227F6C1E4004DB322 /* CustomAssetMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAssetMapper.swift; sourceTree = ""; }; 84CFBC6428756CCB00E93EDA /* EthereumError+Presentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EthereumError+Presentable.swift"; sourceTree = ""; }; 84CFF1CF26526FBC00DB7CF7 /* StakingBondMoreProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StakingBondMoreProtocols.swift; sourceTree = ""; }; @@ -8608,6 +8612,7 @@ 847A25C028D84A3D006AC9F5 /* Governance */ = { isa = PBXGroup; children = ( + 84CEF286290462A700BA25BB /* Validating */, 8453DE5328FD24210055345C /* Subscription */, 8455AB4628F7F07200974E88 /* ViewModel */, 880059D628EEA55500E87B9B /* View */, @@ -11232,6 +11237,15 @@ path = MigrationMappings; sourceTree = ""; }; + 84CEF286290462A700BA25BB /* Validating */ = { + isa = PBXGroup; + children = ( + 84CEF287290462C300BA25BB /* GovernanceValidatorFactory.swift */, + 84CEF289290466A800BA25BB /* GovernanceErrorPresentable.swift */, + ); + path = Validating; + sourceTree = ""; + }; 84CFF1CE26526FBC00DB7CF7 /* StakingBondMore */ = { isa = PBXGroup; children = ( @@ -14759,6 +14773,7 @@ 848DE76626D642670045CD29 /* StorageMigrator.swift in Sources */, F4AE12A1268DD69B0097D1C7 /* MnemonicTextNormalizer.swift in Sources */, 8463A72525E3A82A003B8160 /* DataProviderProxyTrigger.swift in Sources */, + 84CEF28A290466A800BA25BB /* GovernanceErrorPresentable.swift in Sources */, 8460E720284D452E002896E9 /* ParaStkUnstakePresenter+ModalPicker.swift in Sources */, 847F2D4A27AA687C00AFD476 /* AssetListPresenter+Model.swift in Sources */, 847119EB262EFF3800716580 /* ValidatorPayoutInfoFactory.swift in Sources */, @@ -16440,6 +16455,7 @@ 93434E8E407A6C63D8862A21 /* AssetSelectionProtocols.swift in Sources */, 84E25BEC27E87D5400290BF1 /* TransferDataValidatorFactory.swift in Sources */, 8499FE7127BE214A00712589 /* StorageKeyDecodingOperation.swift in Sources */, + 84CEF288290462C300BA25BB /* GovernanceValidatorFactory.swift in Sources */, CDB78A5A733E4A4F1A2C48C8 /* AssetSelectionWireframe.swift in Sources */, 2FCB062A2D873BD72B795DB3 /* AssetSelectionPresenter.swift in Sources */, BEA539EE97A287868FD8BE46 /* AssetSelectionViewFactory.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+ConstantPath.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+ConstantPath.swift index 39c6db75db..978113151e 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+ConstantPath.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+ConstantPath.swift @@ -4,4 +4,8 @@ extension ConvictionVoting { static var voteLockingPeriodPath: ConstantCodingPath { ConstantCodingPath(moduleName: "ConvictionVoting", constantName: "VoteLockingPeriod") } + + static var maxVotes: ConstantCodingPath { + ConstantCodingPath(moduleName: "ConvictionVoting", constantName: "MaxVotes") + } } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index c693cf42ff..1b9ed3c8c0 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -9,6 +9,26 @@ struct ReferendumLocal { let index: ReferendumIdLocal let state: ReferendumStateLocal let proposer: AccountId? + + var canVote: Bool { + switch state { + case .preparing, .deciding: + return true + case .approved, .rejected, .cancelled, .timedOut, .killed, .executed: + return false + } + } + + var trackId: TrackIdLocal? { + switch state { + case let .preparing(model): + return TrackIdLocal(model.track.trackId) + case let .deciding(model): + return TrackIdLocal(model.track.trackId) + case .approved, .rejected, .cancelled, .timedOut, .killed, .executed: + return nil + } + } } struct SupportAndVotesLocal { diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift index 4f409b3f42..66d658525b 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift @@ -2,7 +2,9 @@ import Foundation struct ReferendumAccountVotingDistribution { let votes: [ReferendumIdLocal: ReferendumAccountVoteLocal] + let votedTracks: [TrackIdLocal: Set] let delegatings: [TrackIdLocal: ReferendumDelegatingLocal] + let maxVotesPerTrack: UInt32 func addingVote( _ vote: ReferendumAccountVoteLocal, @@ -13,7 +15,9 @@ struct ReferendumAccountVotingDistribution { return ReferendumAccountVotingDistribution( votes: newVotes, - delegatings: delegatings + votedTracks: votedTracks, + delegatings: delegatings, + maxVotesPerTrack: maxVotesPerTrack ) } @@ -26,7 +30,26 @@ struct ReferendumAccountVotingDistribution { return ReferendumAccountVotingDistribution( votes: votes, - delegatings: newDelegatings + votedTracks: votedTracks, + delegatings: newDelegatings, + maxVotesPerTrack: maxVotesPerTrack + ) + } + + func addingReferendum( + _ referendumIndex: ReferendumIdLocal, + track: TrackIdLocal + ) -> ReferendumAccountVotingDistribution { + var newVotedTracks = votedTracks + var referendums = newVotedTracks[track] ?? Set() + referendums.insert(referendumIndex) + newVotedTracks[track] = referendums + + return ReferendumAccountVotingDistribution( + votes: votes, + votedTracks: newVotedTracks, + delegatings: delegatings, + maxVotesPerTrack: maxVotesPerTrack ) } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 8368db7723..30cee31612 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -298,21 +298,44 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { votesWrapper.addDependency(operations: [codingFactoryOperation]) + let maxVotesOperation = PrimitiveConstantOperation(path: ConvictionVoting.maxVotes) + maxVotesOperation.configurationBlock = { + do { + maxVotesOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + maxVotesOperation.result = .failure(error) + } + } + + maxVotesOperation.addDependency(codingFactoryOperation) + let mappingOperation = ClosureOperation { let voting = try votesWrapper.targetOperation.extractNoCancellableResultData() + let maxVotes = try maxVotesOperation.extractNoCancellableResultData() + + let initVotingLocal = ReferendumAccountVotingDistribution( + votes: [:], + votedTracks: [:], + delegatings: [:], + maxVotesPerTrack: maxVotes + ) - let initVotingLocal = ReferendumAccountVotingDistribution(votes: [:], delegatings: [:]) return voting.reduce(initVotingLocal) { resultVoting, votingKeyValue in let voting = votingKeyValue.value let track = votingKeyValue.key.trackId switch voting { case let .casting(castingVoting): return castingVoting.votes.reduce(resultVoting) { result, vote in + let newResult = result.addingReferendum( + ReferendumIdLocal(vote.pollIndex), + track: TrackIdLocal(track) + ) + guard let localVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { - return result + return newResult } - return result.addingVote(localVote, referendumId: ReferendumIdLocal(vote.pollIndex)) + return newResult.addingVote(localVote, referendumId: ReferendumIdLocal(vote.pollIndex)) } case let .delegating(delegatingVoting): let delegatingLocal = ReferendumDelegatingLocal(remote: delegatingVoting) diff --git a/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift b/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift new file mode 100644 index 0000000000..9e4ac2727f --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift @@ -0,0 +1,77 @@ +import Foundation + +protocol GovernanceErrorPresentable: BaseErrorPresentable { + func presentNotEnoughTokensToVote( + from view: ControllerBackedProtocol, + available: String, + locale: Locale? + ) + + func presentReferendumCompleted( + from view: ControllerBackedProtocol, + locale: Locale? + ) + + func presentAlreadyDelegatingVotes( + from view: ControllerBackedProtocol, + locale: Locale? + ) + + func presentVotesMaximumNumberReached( + from view: ControllerBackedProtocol, + allowed: String, + locale: Locale? + ) +} + +extension GovernanceErrorPresentable where Self: AlertPresentable & ErrorPresentable { + func presentNotEnoughTokensToVote( + from view: ControllerBackedProtocol, + available: String, + locale: Locale? + ) { + let title = R.string.localizable.commonAmountTooBig(preferredLanguages: locale?.rLanguages) + let message = R.string.localizable.govNotEnoughVoteTokens(available, preferredLanguages: locale?.rLanguages) + + let close = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: close, from: view) + } + + func presentReferendumCompleted( + from view: ControllerBackedProtocol, + locale: Locale? + ) { + let title = R.string.localizable.govReferendumCompletedTitle(preferredLanguages: locale?.rLanguages) + let message = R.string.localizable.govReferendumCompletedMessage(preferredLanguages: locale?.rLanguages) + + let close = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: close, from: view) + } + + func presentAlreadyDelegatingVotes( + from view: ControllerBackedProtocol, + locale: Locale? + ) { + let title = R.string.localizable.govAlreadyDelegatingVotesTitle(preferredLanguages: locale?.rLanguages) + let message = R.string.localizable.govAlreadyDelegatingVotesMessage(preferredLanguages: locale?.rLanguages) + + let close = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: close, from: view) + } + + func presentVotesMaximumNumberReached( + from view: ControllerBackedProtocol, + allowed: String, + locale: Locale? + ) { + let title = R.string.localizable.govMaxVotesReachedTitle(preferredLanguages: locale?.rLanguages) + let message = R.string.localizable.govMaxVotesReachedMessage(allowed, preferredLanguages: locale?.rLanguages) + + let close = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: close, from: view) + } +} diff --git a/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift b/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift new file mode 100644 index 0000000000..8842ba9ab0 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift @@ -0,0 +1,223 @@ +import Foundation +import BigInt +import SoraFoundation + +protocol GovernanceValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { + func enoughTokensForVoting( + _ assetBalance: AssetBalance?, + votingAmount: BigUInt?, + assetInfo: AssetBalanceDisplayInfo, + locale: Locale? + ) -> DataValidating + + func enoughTokensForVotingAndFee( + _ assetBalance: AssetBalance?, + votingAmount: BigUInt?, + fee: BigUInt?, + assetInfo: AssetBalanceDisplayInfo, + locale: Locale? + ) -> DataValidating + + func referendumNotEnded( + _ referendum: ReferendumLocal?, + locale: Locale? + ) -> DataValidating + + func notDelegating( + _ accountVotingDistribution: ReferendumAccountVotingDistribution?, + track: TrackIdLocal?, + locale: Locale? + ) -> DataValidating + + func maxVotesNotReached( + _ accountVotingDistribution: ReferendumAccountVotingDistribution?, + track: TrackIdLocal?, + locale: Locale? + ) -> DataValidating +} + +final class GovernanceValidatorFactory { + weak var view: (Localizable & ControllerBackedProtocol)? + + var basePresentable: BaseErrorPresentable { presentable } + let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol + let quantityFormatter: LocalizableResource + let presentable: GovernanceErrorPresentable + + init( + presentable: GovernanceErrorPresentable, + assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, + quantityFormatter: LocalizableResource + ) { + self.presentable = presentable + self.assetBalanceFormatterFactory = assetBalanceFormatterFactory + self.quantityFormatter = quantityFormatter + } +} + +extension GovernanceValidatorFactory: GovernanceValidatorFactoryProtocol { + func enoughTokensForVoting( + _ assetBalance: AssetBalance?, + votingAmount: BigUInt?, + assetInfo: AssetBalanceDisplayInfo, + locale: Locale? + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + + let amountFormatter = self?.assetBalanceFormatterFactory.createTokenFormatter(for: assetInfo) + let amountString: String + + if + let freeInPlank = assetBalance?.freeInPlank, + let amountDecimal = Decimal.fromSubstrateAmount(freeInPlank, precision: assetInfo.assetPrecision) { + amountString = amountFormatter?.value(for: locale ?? Locale.current).stringFromDecimal( + amountDecimal + ) ?? "" + } else { + amountString = "" + } + + self?.presentable.presentNotEnoughTokensToVote( + from: view, + available: amountString, + locale: locale + ) + }, preservesCondition: { + guard + let assetBalance = assetBalance, + let votingAmount = votingAmount else { + return false + } + + return assetBalance.freeInPlank >= votingAmount + }) + } + + func enoughTokensForVotingAndFee( + _ assetBalance: AssetBalance?, + votingAmount: BigUInt?, + fee: BigUInt?, + assetInfo: AssetBalanceDisplayInfo, + locale: Locale? + ) -> DataValidating { + let availableForFee: BigUInt + + if + let assetBalance = assetBalance, + let votingAmount = votingAmount, + assetBalance.freeInPlank >= votingAmount { + availableForFee = min(assetBalance.freeInPlank - votingAmount, assetBalance.transferable) + } else { + availableForFee = 0 + } + + return ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + + let amountFormatter = self?.assetBalanceFormatterFactory.createTokenFormatter( + for: assetInfo + ).value(for: locale ?? Locale.current) + + let amountString: String + + if + let amountDecimal = Decimal.fromSubstrateAmount( + availableForFee, + precision: assetInfo.assetPrecision + ) { + amountString = amountFormatter?.stringFromDecimal(amountDecimal) ?? "" + } else { + amountString = "" + } + + let feeString: String + + if + let feeDecimal = Decimal.fromSubstrateAmount( + fee ?? 0, + precision: assetInfo.assetPrecision + ) { + feeString = amountFormatter?.stringFromDecimal(feeDecimal) ?? "" + } else { + feeString = "" + } + + self?.presentable.presentFeeTooHigh(from: view, balance: amountString, fee: feeString, locale: locale) + }, preservesCondition: { + guard let fee = fee else { + return true + } + + return availableForFee >= fee + }) + } + + func referendumNotEnded(_ referendum: ReferendumLocal?, locale: Locale?) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + + self?.presentable.presentReferendumCompleted(from: view, locale: locale) + }, preservesCondition: { + guard let referendum = referendum else { + return false + } + + return referendum.canVote + }) + } + + func notDelegating( + _ accountVotingDistribution: ReferendumAccountVotingDistribution?, + track: TrackIdLocal?, + locale: Locale? + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + + self?.presentable.presentAlreadyDelegatingVotes(from: view, locale: locale) + }, preservesCondition: { + guard let track = track else { + return true + } + + return accountVotingDistribution?.delegatings[track] == nil + }) + } + + func maxVotesNotReached( + _ accountVotingDistribution: ReferendumAccountVotingDistribution?, + track: TrackIdLocal?, + locale: Locale? + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view, let accountVotingDistribution = accountVotingDistribution else { + return + } + + let allowed = self?.quantityFormatter.value( + for: locale ?? Locale.current + ).string(from: accountVotingDistribution.maxVotesPerTrack as NSNumber) + + self?.presentable.presentVotesMaximumNumberReached(from: view, allowed: allowed ?? "", locale: locale) + }, preservesCondition: { + guard + let track = track, + let accountVotingDistribution = accountVotingDistribution else { + return true + } + + let numberOfVotes = accountVotingDistribution.votedTracks[track]?.count ?? 0 + + return numberOfVotes < Int(accountVotingDistribution.maxVotesPerTrack) + }) + } +} diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 82fd6e6724..ad8a768eab 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1036,3 +1036,11 @@ "gov.referendum.details.dApps.title" = "Use Nova DApp browser"; "gov.referendum.details.timeline.title" = "Timeline"; "gov.your.vote" = "Your vote"; +"common.amount.too.big" = "Amount is too big"; +"gov.not.enough.vote.tokens" = "Sorry, you don’t have enough available tokens to vote. Available to vote: %@"; +"gov.referendum.completed.title" = "Referendum is completed"; +"gov.referendum.completed.message" = "Referendum is completed and voting has finished"; +"gov.already.delegating.votes.title" = "Already delegating votes"; +"gov.already.delegating.votes.message" = "You are delegating votes for selected referendum’s track. Please, either ask your delegatee to vote or remove delegation to be able to vote directly."; +"gov.max.votes.reached.title" = "Maximum number of votes reached"; +"gov.max.votes.reached.message" = "You have reached a maximum of %@ votes for track"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 79728a0715..0b25b49c2d 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1037,3 +1037,11 @@ "gov.referendum.details.dApps.title" = "Использовать Nova DApp браузер"; "gov.referendum.details.timeline.title" = "Статусы"; "gov.your.vote" = "Ваш голос"; +"common.amount.too.big" = "Сумма слишком большая"; +"gov.not.enough.vote.tokens" = "Извините, у Вас недостаточно токенов для голосования. Доступно токенов для голосования: %@"; +"gov.referendum.completed.title" = "Референдум завершен"; +"gov.referendum.completed.message" = "Голосование за референдум завершено"; +"gov.already.delegating.votes.title" = "Голоса делегированы"; +"gov.already.delegating.votes.message" = "Вы делегируете голоса в треке к которому относится выбранный референдум. Пожалуйста, либо попросите делегата проголосовать или отключите делегирование и голосуйте напрямую."; +"gov.max.votes.reached.title" = "Достигнуто максимальное количество голосов"; +"gov.max.votes.reached.message" = "Вы достигли максимального числа голосов %@ в треке"; From 9de79e75a74888ad8dd38d322ad16c63d2e7bd7e Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 23 Oct 2022 11:38:30 +0500 Subject: [PATCH 086/229] add data validating --- novawallet.xcodeproj/project.pbxproj | 8 +++ .../Model/ChainRegistry/ChainModel.swift | 4 ++ .../Operation/Gov2OperationFactory.swift | 37 +++++++------ .../ReferendumVoteConfirmPresenter.swift | 33 +++++++++++- .../ReferendumVoteConfirmProtocols.swift | 2 +- .../ReferendumVoteConfirmViewFactory.swift | 8 +++ .../ReferendumVoteSetupPresenter.swift | 54 +++++++++++++++---- .../ReferendumVoteSetupProtocols.swift | 3 +- .../ReferendumVoteSetupViewFactory.swift | 8 +++ .../ReferendumVoteSetupViewLayout.swift | 2 + .../DataValidationRunner+GovVote.swift | 46 ++++++++++++++++ .../GovernanceVoteValidatingParams.swift | 11 ++++ 12 files changed, 186 insertions(+), 30 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Validating/DataValidationRunner+GovVote.swift create mode 100644 novawallet/Modules/Vote/Governance/Validating/GovernanceVoteValidatingParams.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index c177256c3f..6b6204c1de 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1842,6 +1842,8 @@ 84CEEDE2284E3DCE0039364A /* AccountDetailsNavigationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEEDE1284E3DCE0039364A /* AccountDetailsNavigationCell.swift */; }; 84CEF288290462C300BA25BB /* GovernanceValidatorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEF287290462C300BA25BB /* GovernanceValidatorFactory.swift */; }; 84CEF28A290466A800BA25BB /* GovernanceErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEF289290466A800BA25BB /* GovernanceErrorPresentable.swift */; }; + 84CEF28C290509D600BA25BB /* GovernanceVoteValidatingParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEF28B290509D600BA25BB /* GovernanceVoteValidatingParams.swift */; }; + 84CEF28E29050A3300BA25BB /* DataValidationRunner+GovVote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEF28D29050A3300BA25BB /* DataValidationRunner+GovVote.swift */; }; 84CF00C327F6C1E4004DB322 /* CustomAssetMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CF00C227F6C1E4004DB322 /* CustomAssetMapper.swift */; }; 84CFBC6528756CCB00E93EDA /* EthereumError+Presentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CFBC6428756CCB00E93EDA /* EthereumError+Presentable.swift */; }; 84CFF1E326526FBC00DB7CF7 /* StakingBondMoreProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CFF1CF26526FBC00DB7CF7 /* StakingBondMoreProtocols.swift */; }; @@ -4758,6 +4760,8 @@ 84CEEDE1284E3DCE0039364A /* AccountDetailsNavigationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDetailsNavigationCell.swift; sourceTree = ""; }; 84CEF287290462C300BA25BB /* GovernanceValidatorFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceValidatorFactory.swift; sourceTree = ""; }; 84CEF289290466A800BA25BB /* GovernanceErrorPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceErrorPresentable.swift; sourceTree = ""; }; + 84CEF28B290509D600BA25BB /* GovernanceVoteValidatingParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceVoteValidatingParams.swift; sourceTree = ""; }; + 84CEF28D29050A3300BA25BB /* DataValidationRunner+GovVote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataValidationRunner+GovVote.swift"; sourceTree = ""; }; 84CF00C227F6C1E4004DB322 /* CustomAssetMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAssetMapper.swift; sourceTree = ""; }; 84CFBC6428756CCB00E93EDA /* EthereumError+Presentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EthereumError+Presentable.swift"; sourceTree = ""; }; 84CFF1CF26526FBC00DB7CF7 /* StakingBondMoreProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StakingBondMoreProtocols.swift; sourceTree = ""; }; @@ -11242,6 +11246,8 @@ children = ( 84CEF287290462C300BA25BB /* GovernanceValidatorFactory.swift */, 84CEF289290466A800BA25BB /* GovernanceErrorPresentable.swift */, + 84CEF28B290509D600BA25BB /* GovernanceVoteValidatingParams.swift */, + 84CEF28D29050A3300BA25BB /* DataValidationRunner+GovVote.swift */, ); path = Validating; sourceTree = ""; @@ -14946,6 +14952,7 @@ 84873B0426029B75000A83EE /* StakingEstimationViewModel.swift in Sources */, AE6F7FE32685E812002BBC3E /* ValidatorListFilterViewLayout.swift in Sources */, 847A6C0928817DC700477F77 /* AssetListBaseInteractorProtocol.swift in Sources */, + 84CEF28C290509D600BA25BB /* GovernanceVoteValidatingParams.swift in Sources */, 8425D0EA28FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift in Sources */, 84E25BEE27E8895400290BF1 /* TransferErrorPresentable.swift in Sources */, 84038FF026FFBE0600C73F3F /* JsonLocalStorageSubscriber.swift in Sources */, @@ -16865,6 +16872,7 @@ 882808CA29009CDC00AE8089 /* UIView+frame.swift in Sources */, 4541F886953E046C16E42997 /* LedgerWalletConfirmInteractor.swift in Sources */, 2A652719FB31E3C8FF36F46A /* LedgerWalletConfirmViewFactory.swift in Sources */, + 84CEF28E29050A3300BA25BB /* DataValidationRunner+GovVote.swift in Sources */, 95EBC71EAE906B0DFA758AB8 /* LedgerTxConfirmProtocols.swift in Sources */, 992678FD5D3F9D39FFC2BB53 /* LedgerTxConfirmWireframe.swift in Sources */, ED529AA4ED05E8847C4C067F /* LedgerTxConfirmPresenter.swift in Sources */, diff --git a/novawallet/Common/Model/ChainRegistry/ChainModel.swift b/novawallet/Common/Model/ChainRegistry/ChainModel.swift index d55baf9aac..5df5c38109 100644 --- a/novawallet/Common/Model/ChainRegistry/ChainModel.swift +++ b/novawallet/Common/Model/ChainRegistry/ChainModel.swift @@ -133,6 +133,10 @@ struct ChainModel: Equatable, Codable, Hashable { utilityAssets().first } + func utilityAssetDisplayInfo() -> AssetBalanceDisplayInfo? { + utilityAsset()?.displayInfo(with: icon) + } + var typesUsage: TypesUsage { if let types = types { return types.overridesCommon ? .onlyOwn : .both diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 30cee31612..571c154c44 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -170,6 +170,21 @@ final class Gov2OperationFactory { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) } + + private func createMaxVotesOperation( + dependingOn codingFactoryOperation: BaseOperation + ) -> BaseOperation { + let maxVotesOperation = PrimitiveConstantOperation(path: ConvictionVoting.maxVotes) + maxVotesOperation.configurationBlock = { + do { + maxVotesOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + maxVotesOperation.result = .failure(error) + } + } + + return maxVotesOperation + } } extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { @@ -298,15 +313,7 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { votesWrapper.addDependency(operations: [codingFactoryOperation]) - let maxVotesOperation = PrimitiveConstantOperation(path: ConvictionVoting.maxVotes) - maxVotesOperation.configurationBlock = { - do { - maxVotesOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() - } catch { - maxVotesOperation.result = .failure(error) - } - } - + let maxVotesOperation = createMaxVotesOperation(dependingOn: codingFactoryOperation) maxVotesOperation.addDependency(codingFactoryOperation) let mappingOperation = ClosureOperation { @@ -322,14 +329,11 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { return voting.reduce(initVotingLocal) { resultVoting, votingKeyValue in let voting = votingKeyValue.value - let track = votingKeyValue.key.trackId + let track = TrackIdLocal(votingKeyValue.key.trackId) switch voting { case let .casting(castingVoting): return castingVoting.votes.reduce(resultVoting) { result, vote in - let newResult = result.addingReferendum( - ReferendumIdLocal(vote.pollIndex), - track: TrackIdLocal(track) - ) + let newResult = result.addingReferendum(ReferendumIdLocal(vote.pollIndex), track: track) guard let localVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { return newResult @@ -339,7 +343,7 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { } case let .delegating(delegatingVoting): let delegatingLocal = ReferendumDelegatingLocal(remote: delegatingVoting) - return resultVoting.addingDelegating(delegatingLocal, trackId: TrackIdLocal(track)) + return resultVoting.addingDelegating(delegatingLocal, trackId: track) case .unknown: return resultVoting } @@ -347,8 +351,9 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { } mappingOperation.addDependency(votesWrapper.targetOperation) + mappingOperation.addDependency(maxVotesOperation) - let dependencies = [codingFactoryOperation] + votesWrapper.allOperations + let dependencies = [codingFactoryOperation, maxVotesOperation] + votesWrapper.allOperations return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift index 8d607947d5..d652716744 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift @@ -15,6 +15,7 @@ final class ReferendumVoteConfirmPresenter { let referendumFormatter: LocalizableResource let referendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol let lockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol + let dataValidatingFactory: GovernanceValidatorFactoryProtocol let logger: LoggerProtocol private var assetBalance: AssetBalance? @@ -34,6 +35,7 @@ final class ReferendumVoteConfirmPresenter { vote: ReferendumNewVote, chain: ChainModel, selectedAccount: MetaChainAccountResponse, + dataValidatingFactory: GovernanceValidatorFactoryProtocol, balanceViewModelFactory: BalanceViewModelFactoryProtocol, referendumFormatter: LocalizableResource, referendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol, @@ -46,6 +48,7 @@ final class ReferendumVoteConfirmPresenter { self.vote = vote self.chain = chain self.selectedAccount = selectedAccount + self.dataValidatingFactory = dataValidatingFactory self.balanceViewModelFactory = balanceViewModelFactory self.referendumFormatter = referendumFormatter self.referendumStringsViewModelFactory = referendumStringsViewModelFactory @@ -230,9 +233,35 @@ extension ReferendumVoteConfirmPresenter: ReferendumVoteConfirmPresenterProtocol } func confirm() { - view?.didStartLoading() + guard let assetInfo = chain.utilityAssetDisplayInfo() else { + return + } + + let params = GovernanceVoteValidatingParams( + assetBalance: assetBalance, + referendum: referendum, + newVote: vote, + fee: fee, + votes: votesResult?.value?.votes, + assetInfo: assetInfo + ) - interactor.submit(vote: vote.voteAction) + DataValidationRunner.validateVote( + factory: dataValidatingFactory, + params: params, + selectedLocale: selectedLocale, + feeErrorClosure: { [weak self] in + self?.refreshFee() + }, successClosure: { [weak self] in + guard let strongSelf = self else { + return + } + + strongSelf.view?.didStartLoading() + + strongSelf.interactor.submit(vote: strongSelf.vote.voteAction) + } + ) } func presentSenderDetails() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift index e4a3078831..a74bb81017 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmProtocols.swift @@ -30,4 +30,4 @@ protocol ReferendumVoteConfirmInteractorOutputProtocol: ReferendumVoteInteractor protocol ReferendumVoteConfirmWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, FeeRetryable, MessageSheetPresentable, AddressOptionsPresentable, - ExtrinsicSubmissionPresenting {} + ExtrinsicSubmissionPresenting, GovernanceErrorPresentable {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift index b1ca9f88a9..39916cecdb 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -39,10 +39,17 @@ struct ReferendumVoteConfirmViewFactory { let referendumStringsViewModelFactory = ReferendumDisplayStringFactory() + let dataValidatingFactory = GovernanceValidatorFactory( + presentable: wireframe, + assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), + quantityFormatter: NumberFormatter.quantity.localizableResource() + ) + let presenter = ReferendumVoteConfirmPresenter( vote: newVote, chain: chain, selectedAccount: selectedAccount, + dataValidatingFactory: dataValidatingFactory, balanceViewModelFactory: balanceViewModelFactory, referendumFormatter: NumberFormatter.index.localizableResource(), referendumStringsViewModelFactory: referendumStringsViewModelFactory, @@ -59,6 +66,7 @@ struct ReferendumVoteConfirmViewFactory { ) presenter.view = view + dataValidatingFactory.view = view interactor.presenter = presenter return view diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 406298878e..c58c7ec81c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -15,6 +15,7 @@ final class ReferendumVoteSetupPresenter { let chainAssetViewModelFactory: ChainAssetViewModelFactoryProtocol let referendumStringsViewModelFactory: ReferendumDisplayStringFactoryProtocol let lockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol + let dataValidatingFactory: GovernanceValidatorFactoryProtocol let logger: LoggerProtocol private var assetBalance: AssetBalance? @@ -32,6 +33,7 @@ final class ReferendumVoteSetupPresenter { init( chain: ChainModel, referendumIndex: ReferendumIdLocal, + dataValidatingFactory: GovernanceValidatorFactoryProtocol, balanceViewModelFactory: BalanceViewModelFactoryProtocol, referendumFormatter: LocalizableResource, chainAssetViewModelFactory: ChainAssetViewModelFactoryProtocol, @@ -44,6 +46,7 @@ final class ReferendumVoteSetupPresenter { ) { self.chain = chain self.referendumIndex = referendumIndex + self.dataValidatingFactory = dataValidatingFactory self.balanceViewModelFactory = balanceViewModelFactory self.chainAssetViewModelFactory = chainAssetViewModelFactory self.referendumFormatter = referendumFormatter @@ -235,6 +238,45 @@ final class ReferendumVoteSetupPresenter { blockHash: votesResult.blockHash ) } + + private func performValidation( + for isAye: Bool, + notifying completionBlock: @escaping DataValidationRunnerCompletion + ) { + guard let assetInfo = chain.utilityAssetDisplayInfo() else { + return + } + + let newVote = deriveNewVote(isAye: isAye) + + let params = GovernanceVoteValidatingParams( + assetBalance: assetBalance, + referendum: referendum, + newVote: newVote, + fee: fee, + votes: votesResult?.value?.votes, + assetInfo: assetInfo + ) + + DataValidationRunner.validateVote( + factory: dataValidatingFactory, + params: params, + selectedLocale: selectedLocale, + feeErrorClosure: { [weak self] in + self?.refreshFee() + }, successClosure: completionBlock + ) + } + + private func proceed(isAye: Bool) { + performValidation(for: isAye) { [weak self] in + guard let newVote = self?.deriveNewVote(isAye: isAye) else { + return + } + + self?.wireframe.showConfirmation(from: self?.view, vote: newVote) + } + } } extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { @@ -280,19 +322,11 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { } func proceedNay() { - guard let newVote = deriveNewVote(isAye: false) else { - return - } - - wireframe.showConfirmation(from: view, vote: newVote) + proceed(isAye: false) } func proceedAye() { - guard let newVote = deriveNewVote(isAye: true) else { - return - } - - wireframe.showConfirmation(from: view, vote: newVote) + proceed(isAye: true) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index d4cb34f423..462338a871 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -26,6 +26,7 @@ protocol ReferendumVoteSetupInteractorInputProtocol: ReferendumVoteInteractorInp protocol ReferendumVoteSetupInteractorOutputProtocol: ReferendumVoteInteractorOutputProtocol {} -protocol ReferendumVoteSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, FeeRetryable { +protocol ReferendumVoteSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, FeeRetryable, + GovernanceErrorPresentable { func showConfirmation(from view: ReferendumVoteSetupViewProtocol?, vote: ReferendumNewVote) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index 4e66c39450..27b40ccb97 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -39,9 +39,16 @@ struct ReferendumVoteSetupViewFactory { let referendumStringsViewModelFactory = ReferendumDisplayStringFactory() + let dataValidatingFactory = GovernanceValidatorFactory( + presentable: wireframe, + assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), + quantityFormatter: NumberFormatter.quantity.localizableResource() + ) + let presenter = ReferendumVoteSetupPresenter( chain: chain, referendumIndex: referendum, + dataValidatingFactory: dataValidatingFactory, balanceViewModelFactory: balanceViewModelFactory, referendumFormatter: NumberFormatter.index.localizableResource(), chainAssetViewModelFactory: chainAssetViewModelFactory, @@ -59,6 +66,7 @@ struct ReferendumVoteSetupViewFactory { ) presenter.view = view + dataValidatingFactory.view = view interactor.presenter = presenter return view diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index 3247ca25a2..2875169243 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -13,6 +13,7 @@ final class ReferendumVoteSetupViewLayout: UIView { let button = TriangularedButton() button.applyDefaultStyle() button.triangularedView?.fillColor = R.color.colorGreen()! + button.triangularedView?.highlightedFillColor = R.color.colorGreen()! return button }() @@ -20,6 +21,7 @@ final class ReferendumVoteSetupViewLayout: UIView { let button = TriangularedButton() button.applyDefaultStyle() button.triangularedView?.fillColor = R.color.colorRed()! + button.triangularedView?.highlightedFillColor = R.color.colorRed()! return button }() diff --git a/novawallet/Modules/Vote/Governance/Validating/DataValidationRunner+GovVote.swift b/novawallet/Modules/Vote/Governance/Validating/DataValidationRunner+GovVote.swift new file mode 100644 index 0000000000..e1f1d9113a --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Validating/DataValidationRunner+GovVote.swift @@ -0,0 +1,46 @@ +import Foundation + +extension DataValidationRunner { + static func validateVote( + factory: GovernanceValidatorFactoryProtocol, + params: GovernanceVoteValidatingParams, + selectedLocale: Locale, + feeErrorClosure: @escaping () -> Void, + successClosure: @escaping DataValidationRunnerCompletion + ) { + let runner = DataValidationRunner(validators: [ + factory.enoughTokensForVoting( + params.assetBalance, + votingAmount: params.newVote?.voteAction.amount, + assetInfo: params.assetInfo, + locale: selectedLocale + ), + factory.hasInPlank( + fee: params.fee, + locale: selectedLocale, + precision: params.assetInfo.assetPrecision, + onError: feeErrorClosure + ), + factory.enoughTokensForVotingAndFee( + params.assetBalance, + votingAmount: params.newVote?.voteAction.amount, + fee: params.fee, + assetInfo: params.assetInfo, + locale: selectedLocale + ), + factory.referendumNotEnded(params.referendum, locale: selectedLocale), + factory.notDelegating( + params.votes, + track: params.referendum?.trackId, + locale: selectedLocale + ), + factory.maxVotesNotReached( + params.votes, + track: params.referendum?.trackId, + locale: selectedLocale + ) + ]) + + runner.runValidation(notifyingOnSuccess: successClosure) + } +} diff --git a/novawallet/Modules/Vote/Governance/Validating/GovernanceVoteValidatingParams.swift b/novawallet/Modules/Vote/Governance/Validating/GovernanceVoteValidatingParams.swift new file mode 100644 index 0000000000..2ba35a2110 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Validating/GovernanceVoteValidatingParams.swift @@ -0,0 +1,11 @@ +import Foundation +import BigInt + +struct GovernanceVoteValidatingParams { + let assetBalance: AssetBalance? + let referendum: ReferendumLocal? + let newVote: ReferendumNewVote? + let fee: BigUInt? + let votes: ReferendumAccountVotingDistribution? + let assetInfo: AssetBalanceDisplayInfo +} From 022e3772773728b7413e2d25a45c0c4e7dc7876a Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 23 Oct 2022 16:46:02 +0500 Subject: [PATCH 087/229] add reuse lock buttons --- novawallet.xcodeproj/project.pbxproj | 8 ++ .../Model/ReferendumReuseLockModel.swift | 6 ++ .../ReferendumVoteSetupPresenter.swift | 86 +++++++++++++++--- .../ReferendumVoteSetupProtocols.swift | 3 + .../ReferendumVoteSetupViewController.swift | 24 +++++ .../ReferendumVoteSetupViewLayout.swift | 88 ++++++++++++++++++- .../ReferendumLockReuseViewModel.swift | 10 +++ novawallet/en.lproj/Localizable.strings | 2 + novawallet/ru.lproj/Localizable.strings | 2 + 9 files changed, 217 insertions(+), 12 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumReuseLockModel.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockReuseViewModel.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 6b6204c1de..f43b61478c 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2090,6 +2090,8 @@ 84F1CB3C27CF42B80095D523 /* NftListItemWithPriceCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1CB3B27CF42B80095D523 /* NftListItemWithPriceCell.swift */; }; 84F1CB3E27CF4F5A0095D523 /* BorderedLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1CB3D27CF4F5A0095D523 /* BorderedLabelView.swift */; }; 84F1CB4027CF6BEF0095D523 /* UniquesClassDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1CB3F27CF6BEF0095D523 /* UniquesClassDetails.swift */; }; + 84F1D66B29051A730050F4E3 /* ReferendumLockReuseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66A29051A730050F4E3 /* ReferendumLockReuseViewModel.swift */; }; + 84F1D66D29051F240050F4E3 /* ReferendumReuseLockModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */; }; 84F2FEFA25E797E8008338D5 /* StorageRequestFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FEF925E797E8008338D5 /* StorageRequestFactory.swift */; }; 84F2FEFF25E7ADE7008338D5 /* ValidatorPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FEFE25E7ADE7008338D5 /* ValidatorPrefs.swift */; }; 84F2FF0725E7AF8F008338D5 /* EraValidatorInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FF0625E7AF8F008338D5 /* EraValidatorInfo.swift */; }; @@ -5011,6 +5013,8 @@ 84F1CB3B27CF42B80095D523 /* NftListItemWithPriceCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NftListItemWithPriceCell.swift; sourceTree = ""; }; 84F1CB3D27CF4F5A0095D523 /* BorderedLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BorderedLabelView.swift; sourceTree = ""; }; 84F1CB3F27CF6BEF0095D523 /* UniquesClassDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniquesClassDetails.swift; sourceTree = ""; }; + 84F1D66A29051A730050F4E3 /* ReferendumLockReuseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLockReuseViewModel.swift; sourceTree = ""; }; + 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumReuseLockModel.swift; sourceTree = ""; }; 84F2FEF925E797E8008338D5 /* StorageRequestFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageRequestFactory.swift; sourceTree = ""; }; 84F2FEFE25E7ADE7008338D5 /* ValidatorPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorPrefs.swift; sourceTree = ""; }; 84F2FF0625E7AF8F008338D5 /* EraValidatorInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EraValidatorInfo.swift; sourceTree = ""; }; @@ -6935,6 +6939,7 @@ isa = PBXGroup; children = ( 8425D0DF28FE738D003B782A /* ReferendumVoteSetupInteractorError.swift */, + 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */, ); path = Model; sourceTree = ""; @@ -8766,6 +8771,7 @@ children = ( 84880C3F29016F1500CADB06 /* ReferendumLockChangeViewModel.swift */, 84880C41290172C300CADB06 /* ReferendumLockChangeViewModelFactory.swift */, + 84F1D66A29051A730050F4E3 /* ReferendumLockReuseViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -14842,6 +14848,7 @@ 845B811928F43D4C0040CE84 /* Treasury+CodingPath.swift in Sources */, 842876B224AE059700D91AD8 /* SupportData.swift in Sources */, 84D8754228EB5D66004065BD /* ChainBalanceViewModel.swift in Sources */, + 84F1D66B29051A730050F4E3 /* ReferendumLockReuseViewModel.swift in Sources */, 84893C0524DA8663008F6A3F /* AccountCreationError.swift in Sources */, 84282FBD26D05A54002CA322 /* ChainRegistryFacade.swift in Sources */, 842EBB3B2890B06500B952D8 /* WalletSelectionPresenter.swift in Sources */, @@ -16852,6 +16859,7 @@ CA8D91616B55AF9A02215FBB /* LedgerPerformOperationViewLayout.swift in Sources */, 8CF040889DBCA0E9D40BDC82 /* LedgerDiscoverViewFactory.swift in Sources */, 30542C0BD486FD1583F36BA2 /* LedgerNetworkSelectionProtocols.swift in Sources */, + 84F1D66D29051F240050F4E3 /* ReferendumReuseLockModel.swift in Sources */, 84FBDBE128C884DA00CC1037 /* ParaStkYieldBoostStorageSubscriber.swift in Sources */, C102544345E604976BF7AFFC /* LedgerNetworkSelectionWireframe.swift in Sources */, D71B2C6056D803C196DF4CDA /* LedgerNetworkSelectionPresenter.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumReuseLockModel.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumReuseLockModel.swift new file mode 100644 index 0000000000..ceabf745e9 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumReuseLockModel.swift @@ -0,0 +1,6 @@ +import Foundation + +struct ReferendumReuseLockModel { + let governance: Decimal + let all: Decimal +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index c58c7ec81c..7b5cdd1e49 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -190,6 +190,31 @@ final class ReferendumVoteSetupPresenter { view?.didReceiveConviction(viewModel: UInt(conviction.rawValue)) } + private func provideReuseLocksViewModel() { + guard let model = deriveReuseLocks() else { + return + } + + let governance: String? + + if model.governance > 0 { + governance = balanceViewModelFactory.amountFromValue(model.governance).value(for: selectedLocale) + } else { + governance = nil + } + + let all: String? + + if model.all > 0, model.all != model.governance { + all = balanceViewModelFactory.amountFromValue(model.all).value(for: selectedLocale) + } else { + all = nil + } + + let viewModel = ReferendumLockReuseViewModel(governance: governance, all: all) + view?.didReceiveLockReuse(viewModel: viewModel) + } + private func updateView() { provideReferendumIndex() updateAvailableBalanceView() @@ -199,6 +224,7 @@ final class ReferendumVoteSetupPresenter { updateVotesView() updateLockedAmountView() updateLockedPeriodView() + provideReuseLocksViewModel() } private func deriveNewVote(isAye: Bool = true) -> ReferendumNewVote? { @@ -219,6 +245,20 @@ final class ReferendumVoteSetupPresenter { return ReferendumNewVote(index: referendumIndex, voteAction: voteAction) } + private func deriveReuseLocks() -> ReferendumReuseLockModel? { + let governanceLocksInPlank = lockDiff?.before.maxLockedAmount ?? 0 + let allLocksInPlank = assetBalance?.frozenInPlank ?? 0 + + guard + let precision = chain.utilityAssetDisplayInfo()?.assetPrecision, + let governanceLockDecimal = Decimal.fromSubstrateAmount(governanceLocksInPlank, precision: precision), + let allLockDecimal = Decimal.fromSubstrateAmount(allLocksInPlank, precision: precision) else { + return nil + } + + return ReferendumReuseLockModel(governance: governanceLockDecimal, all: allLockDecimal) + } + private func refreshFee() { guard let newVote = deriveNewVote() else { return @@ -277,6 +317,14 @@ final class ReferendumVoteSetupPresenter { self?.wireframe.showConfirmation(from: self?.view, vote: newVote) } } + + private func updateAfterAmountChanged() { + refreshFee() + refreshLockDiff() + + updateVotesView() + updateAmountPriceView() + } } extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { @@ -289,11 +337,7 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { func updateAmount(_ newValue: Decimal?) { inputResult = newValue.map { .absolute($0) } - refreshFee() - refreshLockDiff() - - updateVotesView() - updateAmountPriceView() + updateAfterAmountChanged() } func selectAmountPercentage(_ percentage: Float) { @@ -301,11 +345,7 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { provideAmountInputViewModel() - refreshFee() - refreshLockDiff() - - updateVotesView() - updateAmountPriceView() + updateAfterAmountChanged() } func selectConvictionValue(_ value: UInt) { @@ -321,6 +361,30 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupPresenterProtocol { refreshLockDiff() } + func reuseGovernanceLock() { + guard let model = deriveReuseLocks() else { + return + } + + inputResult = .absolute(model.governance) + + provideAmountInputViewModel() + + updateAfterAmountChanged() + } + + func reuseAllLock() { + guard let model = deriveReuseLocks() else { + return + } + + inputResult = .absolute(model.all) + + provideAmountInputViewModel() + + updateAfterAmountChanged() + } + func proceedNay() { proceed(isAye: false) } @@ -336,6 +400,7 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto updateLockedAmountView() updateLockedPeriodView() + provideReuseLocksViewModel() } func didReceiveAccountVotes( @@ -368,6 +433,7 @@ extension ReferendumVoteSetupPresenter: ReferendumVoteSetupInteractorOutputProto updateAvailableBalanceView() updateAmountPriceView() provideAmountInputViewModelIfRate() + provideReuseLocksViewModel() refreshFee() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index 462338a871..474dfe6c53 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -11,6 +11,7 @@ protocol ReferendumVoteSetupViewProtocol: ControllerBackedProtocol { func didReceiveConviction(viewModel: UInt) func didReceiveLockedAmount(viewModel: ReferendumLockTransitionViewModel) func didReceiveLockedPeriod(viewModel: ReferendumLockTransitionViewModel) + func didReceiveLockReuse(viewModel: ReferendumLockReuseViewModel) } protocol ReferendumVoteSetupPresenterProtocol: AnyObject { @@ -18,6 +19,8 @@ protocol ReferendumVoteSetupPresenterProtocol: AnyObject { func updateAmount(_ newValue: Decimal?) func selectAmountPercentage(_ percentage: Float) func selectConvictionValue(_ value: UInt) + func reuseGovernanceLock() + func reuseAllLock() func proceedNay() func proceedAye() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift index 581d83dd7d..21214413a2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewController.swift @@ -123,6 +123,14 @@ final class ReferendumVoteSetupViewController: UIViewController, ViewHolder { let amount = rootView.amountInputView.inputViewModel?.decimalAmount presenter.updateAmount(amount) } + + @objc func actionReuseGovernanceLock() { + presenter.reuseGovernanceLock() + } + + @objc func actionReuseAllLock() { + presenter.reuseAllLock() + } } extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol { @@ -165,6 +173,22 @@ extension ReferendumVoteSetupViewController: ReferendumVoteSetupViewProtocol { func didReceiveLockedPeriod(viewModel: ReferendumLockTransitionViewModel) { rootView.lockedPeriodView.bind(viewModel: viewModel) } + + func didReceiveLockReuse(viewModel: ReferendumLockReuseViewModel) { + rootView.bindReuseLocks(viewModel: viewModel, locale: selectedLocale) + + rootView.govLocksReuseButton?.addTarget( + self, + action: #selector(actionReuseGovernanceLock), + for: .touchUpInside + ) + + rootView.allLocksReuseButton?.addTarget( + self, + action: #selector(actionReuseAllLock), + for: .touchUpInside + ) + } } extension ReferendumVoteSetupViewController: AmountInputAccessoryViewDelegate { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index 2875169243..f80105edb9 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -3,9 +3,9 @@ import UIKit final class ReferendumVoteSetupViewLayout: UIView { let containerView: ScrollableContainerView = { let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) - view.stackView.layoutMargins = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 0.0, right: 16.0) + view.stackView.layoutMargins = UIEdgeInsets(top: 8.0, left: 0, bottom: 0, right: 0) view.stackView.isLayoutMarginsRelativeArrangement = true - view.stackView.alignment = .fill + view.stackView.alignment = .center return view }() @@ -35,6 +35,19 @@ final class ReferendumVoteSetupViewLayout: UIView { let amountInputView = NewAmountInputView() + private(set) var govLocksReuseButton: TriangularedButton? + private(set) var allLocksReuseButton: TriangularedButton? + + let lockReuseContainerView: ScrollableContainerView = { + let view = ScrollableContainerView(axis: .horizontal) + view.stackView.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) + view.stackView.isLayoutMarginsRelativeArrangement = true + view.stackView.alignment = .fill + view.stackView.spacing = 8.0 + view.scrollView.showsHorizontalScrollIndicator = false + return view + }() + let convictionView = ReferendumConvictionView() var lockAmountTitleLabel: UILabel { @@ -68,6 +81,57 @@ final class ReferendumVoteSetupViewLayout: UIView { fatalError("init(coder:) has not been implemented") } + func bindReuseLocks(viewModel: ReferendumLockReuseViewModel, locale: Locale) { + if viewModel.governance != nil, govLocksReuseButton == nil { + let button = createReuseLockButton() + lockReuseContainerView.stackView.insertArrangedSubview(button, at: 0) + + govLocksReuseButton = button + } else if viewModel.governance == nil, govLocksReuseButton != nil { + govLocksReuseButton?.removeFromSuperview() + govLocksReuseButton = nil + } + + if viewModel.all != nil, allLocksReuseButton == nil { + let button = createReuseLockButton() + lockReuseContainerView.stackView.addArrangedSubview(button) + + allLocksReuseButton = button + } else if viewModel.all == nil, allLocksReuseButton != nil { + allLocksReuseButton?.removeFromSuperview() + allLocksReuseButton = nil + } + + if let governance = viewModel.governance { + govLocksReuseButton?.imageWithTitleView?.title = R.string.localizable.govReuseGovernanceLocks( + governance, + preferredLanguages: locale.rLanguages + ) + + govLocksReuseButton?.invalidateLayout() + } + + if let all = viewModel.all { + allLocksReuseButton?.imageWithTitleView?.title = R.string.localizable.govReuseAllLocks( + all, + preferredLanguages: locale.rLanguages + ) + + allLocksReuseButton?.invalidateLayout() + } + + lockReuseContainerView.isHidden = !viewModel.hasLocks + + lockReuseContainerView.setNeedsLayout() + } + + private func createReuseLockButton() -> TriangularedButton { + let button = TriangularedButton() + button.applySecondaryDefaultStyle() + button.contentInsets = UIEdgeInsets(top: 6, left: 12, bottom: 6, right: 12) + return button + } + private func setupLayout() { addSubview(nayButton) nayButton.snp.makeConstraints { make in @@ -106,6 +170,14 @@ final class ReferendumVoteSetupViewLayout: UIView { make.height.equalTo(64) } + containerView.stackView.addArrangedSubview(lockReuseContainerView) + lockReuseContainerView.snp.makeConstraints { make in + make.height.equalTo(32.0) + make.width.equalTo(self) + } + + containerView.stackView.setCustomSpacing(16.0, after: lockReuseContainerView) + containerView.stackView.setCustomSpacing(12.0, after: amountInputView) containerView.stackView.addArrangedSubview(convictionView) @@ -125,5 +197,17 @@ final class ReferendumVoteSetupViewLayout: UIView { lockedPeriodView.snp.makeConstraints { make in make.height.equalTo(34.0) } + + setupContentWidth() + } + + private func setupContentWidth() { + containerView.stackView.arrangedSubviews + .filter { $0 !== lockReuseContainerView } + .forEach { + $0.snp.makeConstraints { make in + make.width.equalTo(self).offset(-2 * UIConstants.horizontalInset) + } + } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockReuseViewModel.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockReuseViewModel.swift new file mode 100644 index 0000000000..a7e578b3b9 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockReuseViewModel.swift @@ -0,0 +1,10 @@ +import Foundation + +struct ReferendumLockReuseViewModel { + let governance: String? + let all: String? + + var hasLocks: Bool { + governance != nil || all != nil + } +} diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index ad8a768eab..0a26c8e487 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1044,3 +1044,5 @@ "gov.already.delegating.votes.message" = "You are delegating votes for selected referendum’s track. Please, either ask your delegatee to vote or remove delegation to be able to vote directly."; "gov.max.votes.reached.title" = "Maximum number of votes reached"; "gov.max.votes.reached.message" = "You have reached a maximum of %@ votes for track"; +"gov.reuse.governance.locks" = "Reuse governance lock: %@"; +"gov.reuse.all.locks" = "Reuse all locks: %@"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 0b25b49c2d..b726c491ed 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1045,3 +1045,5 @@ "gov.already.delegating.votes.message" = "Вы делегируете голоса в треке к которому относится выбранный референдум. Пожалуйста, либо попросите делегата проголосовать или отключите делегирование и голосуйте напрямую."; "gov.max.votes.reached.title" = "Достигнуто максимальное количество голосов"; "gov.max.votes.reached.message" = "Вы достигли максимального числа голосов %@ в треке"; +"gov.reuse.governance.locks" = "Заблокированные в голосовании: %@"; +"gov.reuse.all.locks" = "Все заблокированные: %@"; From 8430086c8c26a3cc595d786132a8aeebc724a5fb Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 23 Oct 2022 17:20:08 +0500 Subject: [PATCH 088/229] fix conviction parsing --- .../ConvictionVoting/ConvictionVoting.swift | 24 +++++++++++++++++++ .../ReferendumDetailsViewController.swift | 2 +- .../ReferendumVoteConfirmPresenter.swift | 13 ++++++---- .../Vote/Governance/View/YourVoteView.swift | 9 +++++-- .../ViewModel/ReferendumsModelFactory.swift | 6 +++-- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index f5829f8454..4a34af4bfb 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -87,6 +87,30 @@ enum ConvictionVoting { return nil } } + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "None": + self = .none + case "Locked1x": + self = .locked1x + case "Locked2x": + self = .locked2x + case "Locked3x": + self = .locked3x + case "Locked4x": + self = .locked4x + case "Locked5x": + self = .locked5x + case "Locked6x": + self = .locked6x + default: + self = .unknown + } + } } struct Vote: Codable { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index b15344899e..2be8cd0673 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -126,7 +126,7 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { rootView.fullDetailsView.bind(title: "Full details") didReceive(yourVoteModel: .init( - vote: .init(title: "AYE", description: "Your vote"), + vote: .init(title: "AYE", description: "Your vote", style: .ayeInverse), amount: .init(topValue: "30 votes", bottomValue: "10 KSM × 3x") )) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift index d652716744..8644592e5b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift @@ -133,18 +133,21 @@ final class ReferendumVoteConfirmPresenter { locale: selectedLocale ) - let voteSide: String + let voteSideString: String + let voteSideStyle: YourVoteView.Style if vote.voteAction.isAye { - voteSide = R.string.localizable.governanceAye(preferredLanguages: selectedLocale.rLanguages) + voteSideString = R.string.localizable.governanceAye(preferredLanguages: selectedLocale.rLanguages) + voteSideStyle = .ayeInverse } else { - voteSide = R.string.localizable.governanceNay(preferredLanguages: selectedLocale.rLanguages) + voteSideString = R.string.localizable.governanceNay(preferredLanguages: selectedLocale.rLanguages) + voteSideStyle = .nayInverse } - let title = R.string.localizable.govYourVote(preferredLanguages: selectedLocale.rLanguages) + let voteDescription = R.string.localizable.govYourVote(preferredLanguages: selectedLocale.rLanguages) let viewModel = YourVoteRow.Model( - vote: .init(title: title, description: voteSide), + vote: .init(title: voteSideString.uppercased(), description: voteDescription, style: voteSideStyle), amount: .init(topValue: votesString ?? "", bottomValue: convictionString) ) diff --git a/novawallet/Modules/Vote/Governance/View/YourVoteView.swift b/novawallet/Modules/Vote/Governance/View/YourVoteView.swift index bc6bbf94aa..876a66dc14 100644 --- a/novawallet/Modules/Vote/Governance/View/YourVoteView.swift +++ b/novawallet/Modules/Vote/Governance/View/YourVoteView.swift @@ -93,11 +93,16 @@ extension YourVoteView { struct Model { let title: String let description: String + let style: YourVoteView.Style } func bind(viewModel: Model?) { typeView.titleLabel.text = viewModel?.title voteLabel.text = viewModel?.description + + if let style = viewModel?.style { + apply(style: style) + } } } @@ -132,7 +137,7 @@ extension YourVoteView.Style { ) static let nay = YourVoteView.Style( voteLabel: .votes, - typeView: .ayeType, + typeView: .nayType, mode: .typeTitle ) static let ayeInverse = YourVoteView.Style( @@ -142,7 +147,7 @@ extension YourVoteView.Style { ) static let nayInverse = YourVoteView.Style( voteLabel: .votes, - typeView: .ayeType, + typeView: .nayType, mode: .titleType ) } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 8c75e64a1c..f407ce6ec6 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -158,11 +158,13 @@ final class ReferendumsModelFactory { } let ayesModel = votes.ayes > 0 ? YourVoteView.Model( title: Strings.governanceAye(preferredLanguages: locale.rLanguages).uppercased(), - description: formatVotes(votes.ayes) + description: formatVotes(votes.ayes), + style: .aye ) : nil let naysModel = votes.nays > 0 ? YourVoteView.Model( title: Strings.governanceNay(preferredLanguages: locale.rLanguages).uppercased(), - description: formatVotes(votes.nays) + description: formatVotes(votes.nays), + style: .nay ) : nil return .init( aye: ayesModel, From 0961adbe4c947be388d4e8f4f9ef15c30bf1a5d1 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 23 Oct 2022 22:57:46 +0500 Subject: [PATCH 089/229] add test logs --- .../Common/Services/ChainRegistry/ChainRegistryTests.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/novawalletTests/Common/Services/ChainRegistry/ChainRegistryTests.swift b/novawalletTests/Common/Services/ChainRegistry/ChainRegistryTests.swift index fe694270cc..bd72a7c87b 100644 --- a/novawalletTests/Common/Services/ChainRegistry/ChainRegistryTests.swift +++ b/novawalletTests/Common/Services/ChainRegistry/ChainRegistryTests.swift @@ -103,7 +103,8 @@ class ChainRegistryTests: XCTestCase { runtimeSyncService: runtimeSyncService, commonTypesSyncService: commonTypesSyncService, chainProvider: chainProvider, - specVersionSubscriptionFactory: specVersionSubscriptionFactory + specVersionSubscriptionFactory: specVersionSubscriptionFactory, + logger: Logger.shared ) registry.syncUp() From b69a6e0181b37c8a3f519a350dbe0624714f64ad Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Sun, 23 Oct 2022 22:35:50 +0300 Subject: [PATCH 090/229] added price --- .../ReferendumFullDetailsPresenter.swift | 74 +++++++++++++++++-- .../ReferendumFullDetailsViewFactory.swift | 6 +- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index 41a516eb5a..4a7dd4d0d2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -1,11 +1,14 @@ import Foundation import SubstrateSdk +import SoraFoundation final class ReferendumFullDetailsPresenter { weak var view: ReferendumFullDetailsViewProtocol? let wireframe: ReferendumFullDetailsWireframeProtocol let interactor: ReferendumFullDetailsInteractorInputProtocol let chainIconGenerator: IconGenerating + let priceAssetInfoFactory: PriceAssetInfoFactoryProtocol + let assetFormatterFactory: AssetBalanceFormatterFactoryProtocol let chain: ChainModel let referendum: ReferendumLocal @@ -21,7 +24,10 @@ final class ReferendumFullDetailsPresenter { chain: ChainModel, referendum: ReferendumLocal, actionDetails: ReferendumActionLocal, - identities: [AccountAddress: AccountIdentity] + identities: [AccountAddress: AccountIdentity], + localizationManager: LocalizationManagerProtocol, + currencyManager: CurrencyManagerProtocol, + assetFormatterFactory: AssetBalanceFormatterFactory ) { self.interactor = interactor self.wireframe = wireframe @@ -30,6 +36,10 @@ final class ReferendumFullDetailsPresenter { self.actionDetails = actionDetails self.identities = identities self.chainIconGenerator = chainIconGenerator + priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) + self.assetFormatterFactory = assetFormatterFactory + self.currencyManager = currencyManager + self.localizationManager = localizationManager } private func updateView() { @@ -98,11 +108,51 @@ final class ReferendumFullDetailsPresenter { return DrawableIconViewModel(icon: icon) } - + private func updatePriceDependentViews() { - view?.didReceive(deposit: .init(topValue: "3.33333 KSM", - bottomValue: "$200"), - title: "Deposit") + guard let utilityAsset = chain.utilityAsset() else { + return + } + guard let amountInPlank = actionDetails.amountSpendDetails?.amount else { + return + } + let amount = Decimal.fromSubstrateAmount( + amountInPlank, + precision: Int16(utilityAsset.precision) + ) ?? 0.0 + + let formattedAmount = formatAmount( + amount, + assetDisplayInfo: utilityAsset.displayInfo, + locale: selectedLocale + ) + let price = formatPrice(amount: amount, priceData: price, locale: selectedLocale) + view?.didReceive( + deposit: .init( + topValue: formattedAmount, + bottomValue: price + ), + title: "Deposit" + ) + } + + private func formatPrice(amount: Decimal, priceData: PriceData?, locale: Locale) -> String { + guard let currencyManager = currencyManager else { + return "" + } + let currencyId = priceData?.currencyId ?? currencyManager.selectedCurrency.id + let assetDisplayInfo = priceAssetInfoFactory.createAssetBalanceDisplayInfo(from: currencyId) + let priceFormatter = assetFormatterFactory.createTokenFormatter(for: assetDisplayInfo) + return priceFormatter.value(for: locale).stringFromDecimal(amount) ?? "" + } + + private func formatAmount( + _ amount: Decimal, + assetDisplayInfo: AssetBalanceDisplayInfo, + locale: Locale + ) -> String { + let priceFormatter = assetFormatterFactory.createTokenFormatter(for: assetDisplayInfo) + return priceFormatter.value(for: locale).stringFromDecimal(amount) ?? "" } } @@ -126,3 +176,17 @@ extension ReferendumFullDetailsPresenter: ReferendumFullDetailsInteractorOutputP print("Received error: \(error.localizedDescription)") } } + +extension ReferendumFullDetailsPresenter: Localizable { + func applyLocalization() { + if view?.isSetup == true { + updateView() + } + } +} + +extension ReferendumFullDetailsPresenter: SelectedCurrencyDepending { + func applyCurrency() { + updatePriceDependentViews() + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift index 8c5c34e044..fe7776a59d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift @@ -1,5 +1,6 @@ import Foundation import SubstrateSdk +import SoraFoundation struct ReferendumFullDetailsViewFactory { static func createView( @@ -31,7 +32,10 @@ struct ReferendumFullDetailsViewFactory { chain: chain, referendum: referendum, actionDetails: actionDetails, - identities: identities + identities: identities, + localizationManager: LocalizationManager.shared, + currencyManager: currencyManager, + assetFormatterFactory: AssetBalanceFormatterFactory() ) let view = ReferendumFullDetailsViewController(presenter: presenter) From 15d52c2cf59ca1fc9c452bb5e11d205451dc5787 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Sun, 23 Oct 2022 23:16:28 +0300 Subject: [PATCH 091/229] fixes --- .../ReferendumFullDetailsPresenter.swift | 3 +++ .../ReferendumFullDetailsViewFactory.swift | 2 +- .../ReferendumFullDetailsViewLayout.swift | 8 +++++++- .../Modules/Vote/Governance/View/UILabel+Style.swift | 4 ++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index 4a7dd4d0d2..f3cc10b01c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -79,6 +79,8 @@ final class ReferendumFullDetailsPresenter { supportCurve: supportCurveModel, callHash: callHashModel ) + + updatePriceDependentViews() } private func getProposer() -> (name: String, icon: ImageViewModelProtocol?)? { @@ -159,6 +161,7 @@ final class ReferendumFullDetailsPresenter { extension ReferendumFullDetailsPresenter: ReferendumFullDetailsPresenterProtocol { func setup() { interactor.setup() + updateView() } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift index fe7776a59d..f1c463e4f9 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift @@ -37,7 +37,7 @@ struct ReferendumFullDetailsViewFactory { currencyManager: currencyManager, assetFormatterFactory: AssetBalanceFormatterFactory() ) - + interactor.presenter = presenter let view = ReferendumFullDetailsViewController(presenter: presenter) presenter.view = view diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index df6ffa14cf..9c7655229e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -22,13 +22,19 @@ final class ReferendumFullDetailsViewLayout: UIView { var supportCurve: StackTableCell? var callHash: StackInfoTableCell? - let jsonTitle: UILabel = .init(style: .rowTitle) + let jsonTitle: UILabel = .init(style: .caption1White64) let jsonView: BlurredView = .create { $0.view.allowsEditingTextAttributes = false + $0.view.isScrollEnabled = false + $0.view.backgroundColor = .clear + $0.view.textAlignment = .left + $0.contentInsets = .zero } override init(frame: CGRect) { super.init(frame: frame) + + setup() } @available(*, unavailable) diff --git a/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift index 676f7ba05d..dc0ddebb8a 100644 --- a/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift +++ b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift @@ -76,6 +76,10 @@ extension UILabel.Style { textColor: R.color.colorWhite64()!, font: .regularFootnote ) + static let caption1White64 = UILabel.Style( + textColor: R.color.colorWhite64()!, + font: .caption1 + ) } extension UILabel.Style { From 550adf0f7e66631e9307ae5444cc9c40c8df5ff7 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 24 Oct 2022 12:45:34 +0500 Subject: [PATCH 092/229] base account details model --- novawallet.xcodeproj/project.pbxproj | 4 + .../Governance/Model/ReferendumLocal.swift | 19 +- .../ReferendumDetailsPresenter.swift | 196 +++++++++++++++++- .../ReferendumDetailsViewController.swift | 1 - .../ReferendumDetailsViewLayout.swift | 2 + .../View/ReferendumDetailsTitleView.swift | 27 +-- .../ReferendumVotingStatusDetailsView.swift | 4 + .../View/ReferendumVotingStatusView.swift | 18 ++ .../View/TrackTagsView.swift | 36 ++++ .../ReferendumDetails/View/VoteRowView.swift | 5 +- .../ReferendumDisplayStringFactory.swift | 76 +++++++ .../ViewModel/ReferendumVotesViewModel.swift | 6 + .../ViewModel/ReferendumsModelFactory.swift | 25 +++ novawallet/en.lproj/Localizable.strings | 4 + novawallet/ru.lproj/Localizable.strings | 4 + 15 files changed, 390 insertions(+), 37 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ViewModel/ReferendumVotesViewModel.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index f43b61478c..a0d2237090 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2092,6 +2092,7 @@ 84F1CB4027CF6BEF0095D523 /* UniquesClassDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1CB3F27CF6BEF0095D523 /* UniquesClassDetails.swift */; }; 84F1D66B29051A730050F4E3 /* ReferendumLockReuseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66A29051A730050F4E3 /* ReferendumLockReuseViewModel.swift */; }; 84F1D66D29051F240050F4E3 /* ReferendumReuseLockModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */; }; + 84F1D66F29066F740050F4E3 /* ReferendumVotesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */; }; 84F2FEFA25E797E8008338D5 /* StorageRequestFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FEF925E797E8008338D5 /* StorageRequestFactory.swift */; }; 84F2FEFF25E7ADE7008338D5 /* ValidatorPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FEFE25E7ADE7008338D5 /* ValidatorPrefs.swift */; }; 84F2FF0725E7AF8F008338D5 /* EraValidatorInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FF0625E7AF8F008338D5 /* EraValidatorInfo.swift */; }; @@ -5015,6 +5016,7 @@ 84F1CB3F27CF6BEF0095D523 /* UniquesClassDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniquesClassDetails.swift; sourceTree = ""; }; 84F1D66A29051A730050F4E3 /* ReferendumLockReuseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLockReuseViewModel.swift; sourceTree = ""; }; 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumReuseLockModel.swift; sourceTree = ""; }; + 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotesViewModel.swift; sourceTree = ""; }; 84F2FEF925E797E8008338D5 /* StorageRequestFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageRequestFactory.swift; sourceTree = ""; }; 84F2FEFE25E7ADE7008338D5 /* ValidatorPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorPrefs.swift; sourceTree = ""; }; 84F2FF0625E7AF8F008338D5 /* EraValidatorInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EraValidatorInfo.swift; sourceTree = ""; }; @@ -7930,6 +7932,7 @@ 8455AB4428F7F05400974E88 /* ReferendumStatusViewModelFactory.swift */, 8455AB4928F80D9300974E88 /* ReferendumTrackType.swift */, 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */, + 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -15409,6 +15412,7 @@ 84D8F15D24D8178000AF43E9 /* IconWithTitleViewModel.swift in Sources */, 844DB61F262D9C070025A8F0 /* ChainHistoryRange.swift in Sources */, 842A737127DB7EF1006EE1EA /* OperationSlashViewModel.swift in Sources */, + 84F1D66F29066F740050F4E3 /* ReferendumVotesViewModel.swift in Sources */, 84C5ADE22813E8C1006D7388 /* GradientBannerInfoView.swift in Sources */, 8490142C24A935FE008F705E /* ErrorPresentable.swift in Sources */, 84DF21A5253473B0005454AE /* ModalInfoFactory.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 1b9ed3c8c0..9204c2b41d 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -20,11 +20,26 @@ struct ReferendumLocal { } var trackId: TrackIdLocal? { + track.map { TrackIdLocal($0.trackId) } + } + + var track: GovernanceTrackLocal? { + switch state { + case let .preparing(model): + return model.track + case let .deciding(model): + return model.track + case .approved, .rejected, .cancelled, .timedOut, .killed, .executed: + return nil + } + } + + var voting: ReferendumStateLocal.Voting? { switch state { case let .preparing(model): - return TrackIdLocal(model.track.trackId) + return model.voting case let .deciding(model): - return TrackIdLocal(model.track.trackId) + return model.voting case .approved, .rejected, .cancelled, .timedOut, .killed, .executed: return nil } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 4c6443055e..577e9425dd 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -1,10 +1,17 @@ import Foundation import SoraFoundation +import SubstrateSdk final class ReferendumDetailsPresenter { + static let readMoreThreshold = 180 + weak var view: ReferendumDetailsViewProtocol? let wireframe: ReferendumDetailsWireframeProtocol let interactor: ReferendumDetailsInteractorInputProtocol + let balanceViewModelFactory: BalanceViewModelFactoryProtocol + let referendumFormatter: LocalizableResource + let referendumViewModelFactory: ReferendumsModelFactoryProtocol + let referendumStringsFactory: ReferendumDisplayStringFactoryProtocol let chain: ChainModel let logger: LoggerProtocol @@ -18,25 +25,189 @@ final class ReferendumDetailsPresenter { private var blockNumber: BlockNumber? private var blockTime: BlockTime? + private lazy var iconGenerator = PolkadotIconGenerator() + init( + chain: ChainModel, interactor: ReferendumDetailsInteractorInputProtocol, wireframe: ReferendumDetailsWireframeProtocol, + referendumViewModelFactory: ReferendumsModelFactoryProtocol, + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + referendumFormatter: LocalizableResource, + referendumStringsFactory: ReferendumDisplayStringFactoryProtocol, referendum: ReferendumLocal, - chain: ChainModel, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol ) { self.interactor = interactor self.wireframe = wireframe + self.referendumViewModelFactory = referendumViewModelFactory + self.referendumStringsFactory = referendumStringsFactory + self.balanceViewModelFactory = balanceViewModelFactory + self.referendumFormatter = referendumFormatter self.referendum = referendum self.chain = chain self.logger = logger self.localizationManager = localizationManager } + + private func provideReferendumInfoViewModel() { + let referendumIndex = referendumFormatter.value(for: selectedLocale).string( + from: referendum.index as NSNumber + ) + + let trackViewModel = referendum.track.map { + ReferendumTrackType.createViewModel(from: $0.name, chain: chain, locale: selectedLocale) + } + + let viewModel = TrackTagsView.Model(titleIcon: trackViewModel, referendumNumber: referendumIndex) + view?.didReceive(trackTagsModel: viewModel) + } + + private func provideTitleViewModel() { + let accountIcon: DrawableIconViewModel? + let accountDisplayName: String? + + if + let proposer = referendum.proposer, + let identities = identities, + let address = try? proposer.toAddress(using: chain.chainFormat) { + accountIcon = (try? iconGenerator.generateFromAccountId(proposer)).map { + DrawableIconViewModel(icon: $0) + } + + accountDisplayName = identities[address]?.displayName ?? address + } else { + accountIcon = nil + accountDisplayName = nil + } + + let detailsLength = referendumMetadata?.details.count ?? 0 + + let shouldReadMore = detailsLength > Self.readMoreThreshold + + let viewModel = ReferendumDetailsTitleView.Model( + accountIcon: accountIcon, + accountName: accountDisplayName, + title: referendumMetadata?.name ?? "", + description: referendumMetadata?.details ?? "", + shouldReadMore: shouldReadMore + ) + + view?.didReceive(titleModel: viewModel) + } + + private func provideRequestedAmount() { + guard + let requestedAmount = actionDetails?.amountSpendDetails?.amount, + let precision = chain.utilityAssetDisplayInfo()?.assetPrecision, + let decimalAmount = Decimal.fromSubstrateAmount(requestedAmount, precision: precision) else { + view?.didReceive(requestedAmount: nil) + return + } + + let balanceViewModel = balanceViewModelFactory.balanceFromPrice(decimalAmount, priceData: price).value( + for: selectedLocale + ) + + let viewModel: RequestedAmountRow.Model = .init( + title: R.string.localizable.commonRequestedAmount(preferredLanguages: selectedLocale.rLanguages), + amount: .init( + topValue: balanceViewModel.amount, + bottomValue: balanceViewModel.price + ) + ) + + view?.didReceive(requestedAmount: viewModel) + } + + private func provideYourVote() { + if let accountVotes = accountVotes { + let viewModel = referendumStringsFactory.createYourVotesViewModel( + from: accountVotes, + chain: chain, + locale: selectedLocale + ) + + view?.didReceive(yourVoteModel: viewModel) + } else { + view?.didReceive(yourVoteModel: nil) + } + } + + private func provideVotingDetails() { + guard + let blockNumber = blockNumber, + let blockTime = blockTime else { + return + } + + let chainInfo = ReferendumsModelFactoryInput.ChainInformation( + chain: chain, + currentBlock: blockNumber, + blockDuration: blockTime + ) + + let referendumViewModel = referendumViewModelFactory.createViewModel( + from: referendum, + metadata: referendumMetadata, + vote: accountVotes, + chainInfo: chainInfo, + selectedLocale: selectedLocale + ) + + let votingProgress = referendumViewModel.progress + let status: ReferendumVotingStatusView.Model = .init( + status: .init( + name: referendumViewModel.referendumInfo.status.name, + kind: .init(infoKind: referendumViewModel.referendumInfo.status.kind) + ), + time: referendumViewModel.referendumInfo.time.map { .init(titleIcon: $0.titleIcon, isUrgent: $0.isUrgent) }, + title: R.string.localizable.govDetailsVotingStatus(preferredLanguages: selectedLocale.rLanguages) + ) + + let button: String? + + if referendum.canVote { + if accountVotes != nil { + button = R.string.localizable.govRevote(preferredLanguages: selectedLocale.rLanguages) + } else { + button = R.string.localizable.govVote(preferredLanguages: selectedLocale.rLanguages) + } + } else { + button = nil + } + + let votes = referendumStringsFactory.createReferendumVotes( + from: referendum, + chain: chain, + locale: selectedLocale + ) + + let viewModel = ReferendumVotingStatusDetailsView.Model( + status: status, + votingProgress: votingProgress, + aye: votes?.ayes, + nay: votes?.nays, + buttonText: button + ) + + view?.didReceive(votingDetails: viewModel) + } + + private func updateView() { + provideReferendumInfoViewModel() + provideTitleViewModel() + provideRequestedAmount() + provideYourVote() + provideVotingDetails() + } } extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { func setup() { + updateView() + interactor.setup() } @@ -49,49 +220,52 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol func didReceiveReferendum(_ referendum: ReferendumLocal) { self.referendum = referendum - logger.info("Did receive referendum") + provideReferendumInfoViewModel() + provideVotingDetails() + provideTitleViewModel() } func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) { self.actionDetails = actionDetails - logger.info("Did receive action details") + provideTitleViewModel() + provideRequestedAmount() } func didReceiveAccountVotes(_ votes: ReferendumAccountVoteLocal?) { accountVotes = votes - logger.info("Did receive account votes") + provideYourVote() } func didReceiveMetadata(_ referendumMetadata: ReferendumMetadataLocal?) { self.referendumMetadata = referendumMetadata - logger.info("Did receive metadata") + provideTitleViewModel() } func didReceiveIdentities(_ identities: [AccountAddress: AccountIdentity]) { self.identities = identities - logger.info("Did receive identity") + provideTitleViewModel() } func didReceivePrice(_ price: PriceData?) { self.price = price - logger.info("Did receive price") + provideRequestedAmount() } func didReceiveBlockNumber(_ blockNumber: BlockNumber) { self.blockNumber = blockNumber - logger.info("Did receive block number") + provideVotingDetails() } func didReceiveBlockTime(_ blockTime: BlockTime) { self.blockTime = blockTime - logger.info("Did receive block time") + provideVotingDetails() } func didReceiveError(_ error: ReferendumDetailsInteractorError) { @@ -120,6 +294,8 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol extension ReferendumDetailsPresenter: Localizable { func applyLocalization() { - if let view = view, view.isSetup {} + if let view = view, view.isSetup { + updateView() + } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 2be8cd0673..98af64939e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -26,7 +26,6 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { setupHandlers() presenter.setup() - setSamples() } private func setupHandlers() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 4097ea43f2..adf5551301 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -22,6 +22,8 @@ final class ReferendumDetailsViewLayout: UIView { override init(frame: CGRect) { super.init(frame: frame) + backgroundColor = R.color.colorBlack() + setupLayout() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index 626a5eac49..5ef6a77000 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -1,23 +1,5 @@ import UIKit -extension TrackTagsView: BindableView { - struct Model { - let titleIcon: TitleIconViewModel - let referendumNumber: String? - } - - func bind(viewModel: Model) { - if let referendumNumber = viewModel.referendumNumber { - numberLabel.isHidden = false - numberLabel.titleLabel.text = referendumNumber - } else { - numberLabel.isHidden = true - } - - trackNameView.iconDetailsView.bind(viewModel: viewModel.titleIcon) - } -} - final class ReferendumDetailsTitleView: UIView { let addressView = PolkadotIconDetailsView() let infoImageView = UIImageView() @@ -78,10 +60,10 @@ final class ReferendumDetailsTitleView: UIView { extension ReferendumDetailsTitleView { struct Model { let accountIcon: DrawableIconViewModel? - let accountName: String + let accountName: String? let title: String let description: String - let buttonText: String + let shouldReadMore: Bool } func bind(viewModel: Model) { @@ -91,6 +73,8 @@ extension ReferendumDetailsTitleView { } addressView.titleLabel.text = viewModel.accountName + addressView.isHidden = viewModel.accountIcon == nil && viewModel.accountName == nil + let titleAttributedString = NSAttributedString( string: viewModel.title, attributes: titleAttributes @@ -104,7 +88,8 @@ extension ReferendumDetailsTitleView { referendumInfo.append(NSAttributedString(string: "\n")) referendumInfo.append(descriptionAttributedString) textView.attributedText = referendumInfo - moreButton.setTitle(viewModel.buttonText, for: .normal) + + moreButton.isHidden = viewModel.shouldReadMore } private var titleAttributes: [NSAttributedString.Key: Any] { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift index d931916a4c..9a06f707d7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -58,6 +58,10 @@ final class ReferendumVotingStatusDetailsView: RoundedView { content.snp.makeConstraints { $0.edges.equalToSuperview().inset(16) } + + voteButton.snp.makeConstraints { make in + make.height.equalTo(44.0) + } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift index 409e5021f6..926f2ccdb5 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift @@ -61,6 +61,18 @@ extension ReferendumVotingStatusView { enum StatusKind { case positive case negative + case neutral + + init(infoKind: ReferendumInfoView.Model.StatusKind) { + switch infoKind { + case .positive: + self = .positive + case .negative: + self = .negative + case .neutral: + self = .neutral + } + } } func bind(viewModel: Model) { @@ -73,6 +85,8 @@ extension ReferendumVotingStatusView { statusLabel.apply(style: .positiveStatusLabel) case .negative: statusLabel.apply(style: .negativeStatusLabel) + case .neutral: + statusLabel.apply(style: .neutralStatusLabel) } } @@ -95,5 +109,9 @@ private extension UILabel.Style { textColor: R.color.colorRedFF3A69(), font: .boldTitle2 ) + static let neutralStatusLabel = UILabel.Style( + textColor: R.color.colorWhite64(), + font: .boldTitle2 + ) static let title = UILabel.Style.footnoteWhite64 } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift index d6caa5a75b..4079c93765 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift @@ -16,6 +16,8 @@ final class TrackTagsView: UIView { $0.titleLabel.numberOfLines = 1 } + private(set) var trackIconViewModel: ImageViewModelProtocol? + override init(frame: CGRect) { super.init(frame: frame) setupLayout() @@ -40,3 +42,37 @@ final class TrackTagsView: UIView { } } } + +extension TrackTagsView: BindableView { + struct Model { + let titleIcon: ReferendumInfoView.Model.Track? + let referendumNumber: String? + } + + func bind(viewModel: Model) { + if let referendumNumber = viewModel.referendumNumber { + numberLabel.isHidden = false + numberLabel.titleLabel.text = referendumNumber + } else { + numberLabel.isHidden = true + } + + trackIconViewModel?.cancel(on: trackNameView.iconDetailsView.imageView) + trackIconViewModel = nil + + if let titleIcon = viewModel.titleIcon { + trackNameView.isHidden = false + trackNameView.iconDetailsView.detailsLabel.text = titleIcon.title + + trackIconViewModel = titleIcon.icon + let size = trackNameView.iconDetailsView.iconWidth + trackIconViewModel?.loadImage( + on: trackNameView.iconDetailsView.imageView, + targetSize: CGSize(width: size, height: size), + animated: true + ) + } else { + trackNameView.isHidden = true + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift index a0dd49ca70..e0181b865e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift @@ -76,13 +76,12 @@ extension VoteRowView: BindableView { struct Model { let title: String let votes: String - let tokens: String + let tokens: String? } func bind(viewModel: Model) { titleLabel.text = viewModel.title - valueView.valueTop.text = viewModel.votes - valueView.valueBottom.text = viewModel.tokens + valueView.bind(topValue: viewModel.votes, bottomValue: viewModel.tokens) } } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift index eb0b0df67f..aa78f7eab6 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift @@ -12,6 +12,82 @@ protocol ReferendumDisplayStringFactoryProtocol { ) -> String? } +extension ReferendumDisplayStringFactoryProtocol { + func createReferendumVotes( + from referendum: ReferendumLocal, + chain: ChainModel, + locale: Locale + ) -> ReferendumVotesViewModel? { + guard let voting = referendum.voting else { + return nil + } + + let ayesString: String? + let naysString: String? + + switch voting { + case let .supportAndVotes(model): + ayesString = createVotes(from: model.ayes, chain: chain, locale: locale) + naysString = createVotes(from: model.nays, chain: chain, locale: locale) + } + + let aye: VoteRowView.Model? = ayesString.map { + .init( + title: R.string.localizable.governanceAye(preferredLanguages: locale.rLanguages), + votes: $0, + tokens: nil + ) + } + + let nay: VoteRowView.Model? = naysString.map { + .init( + title: R.string.localizable.governanceNay(preferredLanguages: locale.rLanguages), + votes: $0, + tokens: nil + ) + } + + return ReferendumVotesViewModel(ayes: aye, nays: nay) + } + + func createYourVotesViewModel( + from vote: ReferendumAccountVoteLocal, + chain: ChainModel, + locale: Locale + ) -> YourVoteRow.Model { + let votesString = createVotes( + from: vote.convictionValue.votes(for: vote.totalBalance) ?? 0, + chain: chain, + locale: locale + ) + + let convictionString = createVotesDetails( + from: vote.totalBalance, + conviction: vote.conviction, + chain: chain, + locale: locale + ) + + let voteSideString: String + let voteSideStyle: YourVoteView.Style + + if vote.ayes > 0 { + voteSideString = R.string.localizable.governanceAye(preferredLanguages: locale.rLanguages) + voteSideStyle = .ayeInverse + } else { + voteSideString = R.string.localizable.governanceNay(preferredLanguages: locale.rLanguages) + voteSideStyle = .nayInverse + } + + let voteDescription = R.string.localizable.govYourVote(preferredLanguages: locale.rLanguages) + + return YourVoteRow.Model( + vote: .init(title: voteSideString.uppercased(), description: voteDescription, style: voteSideStyle), + amount: .init(topValue: votesString ?? "", bottomValue: convictionString) + ) + } +} + final class ReferendumDisplayStringFactory: ReferendumDisplayStringFactoryProtocol { let formatterFactory: AssetBalanceFormatterFactoryProtocol diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumVotesViewModel.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumVotesViewModel.swift new file mode 100644 index 0000000000..6bda8649ae --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumVotesViewModel.swift @@ -0,0 +1,6 @@ +import Foundation + +struct ReferendumVotesViewModel { + let ayes: VoteRowView.Model? + let nays: VoteRowView.Model? +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index f407ce6ec6..5a60c81107 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -18,6 +18,14 @@ struct ReferendumsModelFactoryInput { protocol ReferendumsModelFactoryProtocol { func createSections(input: ReferendumsModelFactoryInput) -> [ReferendumsSection] + + func createViewModel( + from referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + vote: ReferendumAccountVoteLocal?, + chainInfo: ReferendumsModelFactoryInput.ChainInformation, + selectedLocale: Locale + ) -> ReferendumView.Model } final class ReferendumsModelFactory { @@ -402,6 +410,23 @@ extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { return sections } + func createViewModel( + from referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + vote: ReferendumAccountVoteLocal?, + chainInfo: ReferendumsModelFactoryInput.ChainInformation, + selectedLocale: Locale + ) -> ReferendumView.Model { + let params = StatusParams( + referendum: referendum, + metadata: metadata, + chainInfo: chainInfo, + votes: vote + ) + + return createReferendumCellViewModel(state: referendum.state, params: params, locale: selectedLocale) + } + private func createReferendumCellViewModel( state: ReferendumStateLocal, params: StatusParams, diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 0a26c8e487..3e57ab6468 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1046,3 +1046,7 @@ "gov.max.votes.reached.message" = "You have reached a maximum of %@ votes for track"; "gov.reuse.governance.locks" = "Reuse governance lock: %@"; "gov.reuse.all.locks" = "Reuse all locks: %@"; +"gov.vote" = "Vote"; +"gov.revote" = "Revote"; +"gov.details.voting.status" = "Voting status"; +"common.requested.amount" = "Requested amount"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index b726c491ed..ab5967be33 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1047,3 +1047,7 @@ "gov.max.votes.reached.message" = "Вы достигли максимального числа голосов %@ в треке"; "gov.reuse.governance.locks" = "Заблокированные в голосовании: %@"; "gov.reuse.all.locks" = "Все заблокированные: %@"; +"gov.vote" = "Голосовать"; +"gov.revote" = "Изменить голос"; +"gov.details.voting.status" = "Статус голосования"; +"common.requested.amount" = "Запрашиваемая сумма"; From e2eb15f4cc11b7917e1de6d5fb2aa9623ac4ffe1 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 25 Oct 2022 00:22:14 +0500 Subject: [PATCH 093/229] bind view model --- novawallet.xcodeproj/project.pbxproj | 12 + .../Assets.xcassets/imageDapps/Contents.json | 6 + .../Contents.json | 12 + .../imageDAppPolkassembly.pdf | Bin 0 -> 4669 bytes .../imageDAppSubsquare.imageset/Contents.json | 12 + .../imageDAppSubsquare.pdf | Bin 0 -> 1328 bytes .../Extension/Foundation/DateFormatter.swift | 10 + .../Governance/Model/GovernanceDApp.swift | 24 ++ .../Governance/Model/ReferendumLocal.swift | 1 + .../Operation/Gov2LocalMappingFactory.swift | 1 + .../ReferendumDetailsInteractorError.swift | 1 + .../ReferendumDetailsInteractor.swift | 40 +++ .../ReferendumDetailsPresenter.swift | 58 +++- .../ReferendumDetailsProtocols.swift | 6 +- .../ReferendumDetailsViewController.swift | 112 +----- .../ReferendumDetailsViewFactory.swift | 42 ++- .../ReferendumDetailsViewLayout.swift | 64 ++-- .../Timeline/ReferendumTimelineView.swift | 25 +- .../ReferendumTimelineViewModelFactory.swift | 322 ++++++++++++++++++ novawallet/Resources/governanceDApps.json | 14 + novawallet/en.lproj/Localizable.strings | 6 +- novawallet/ru.lproj/Localizable.strings | 6 +- 22 files changed, 630 insertions(+), 144 deletions(-) create mode 100644 novawallet/Assets.xcassets/imageDapps/Contents.json create mode 100644 novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/imageDAppPolkassembly.pdf create mode 100644 novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/imageDAppSubsquare.pdf create mode 100644 novawallet/Modules/Vote/Governance/Model/GovernanceDApp.swift create mode 100644 novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift create mode 100644 novawallet/Resources/governanceDApps.json diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index a0d2237090..0f26c08989 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1251,6 +1251,7 @@ 8483B15B28F991550048B295 /* ReferendumVotersTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15A28F991550048B295 /* ReferendumVotersTableViewCell.swift */; }; 8483B15D28FA79620048B295 /* ReferendumDisplayStringFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */; }; 8485D924277E16C400767243 /* DAppBrowserScriptHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */; }; + 8487010A2907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */; }; 84873AFF26028E2B000A83EE /* StakingStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */; }; 84873B0426029B75000A83EE /* StakingEstimationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */; }; 84873B0926029CBD000A83EE /* StakingStateViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873B0826029CBD000A83EE /* StakingStateViewModelFactory.swift */; }; @@ -2093,6 +2094,8 @@ 84F1D66B29051A730050F4E3 /* ReferendumLockReuseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66A29051A730050F4E3 /* ReferendumLockReuseViewModel.swift */; }; 84F1D66D29051F240050F4E3 /* ReferendumReuseLockModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */; }; 84F1D66F29066F740050F4E3 /* ReferendumVotesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */; }; + 84F1D67129068F810050F4E3 /* GovernanceDApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D67029068F810050F4E3 /* GovernanceDApp.swift */; }; + 84F1D67329069FFB0050F4E3 /* governanceDApps.json in Resources */ = {isa = PBXBuildFile; fileRef = 84F1D67229069FFB0050F4E3 /* governanceDApps.json */; }; 84F2FEFA25E797E8008338D5 /* StorageRequestFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FEF925E797E8008338D5 /* StorageRequestFactory.swift */; }; 84F2FEFF25E7ADE7008338D5 /* ValidatorPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FEFE25E7ADE7008338D5 /* ValidatorPrefs.swift */; }; 84F2FF0725E7AF8F008338D5 /* EraValidatorInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FF0625E7AF8F008338D5 /* EraValidatorInfo.swift */; }; @@ -4165,6 +4168,7 @@ 8483B15A28F991550048B295 /* ReferendumVotersTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotersTableViewCell.swift; sourceTree = ""; }; 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDisplayStringFactory.swift; sourceTree = ""; }; 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserScriptHandler.swift; sourceTree = ""; }; + 848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumTimelineViewModelFactory.swift; sourceTree = ""; }; 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingStateMachine.swift; sourceTree = ""; }; 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingEstimationViewModel.swift; sourceTree = ""; }; 84873B0826029CBD000A83EE /* StakingStateViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingStateViewModelFactory.swift; sourceTree = ""; }; @@ -5017,6 +5021,8 @@ 84F1D66A29051A730050F4E3 /* ReferendumLockReuseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLockReuseViewModel.swift; sourceTree = ""; }; 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumReuseLockModel.swift; sourceTree = ""; }; 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotesViewModel.swift; sourceTree = ""; }; + 84F1D67029068F810050F4E3 /* GovernanceDApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceDApp.swift; sourceTree = ""; }; + 84F1D67229069FFB0050F4E3 /* governanceDApps.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = governanceDApps.json; sourceTree = ""; }; 84F2FEF925E797E8008338D5 /* StorageRequestFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageRequestFactory.swift; sourceTree = ""; }; 84F2FEFE25E7ADE7008338D5 /* ValidatorPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorPrefs.swift; sourceTree = ""; }; 84F2FF0625E7AF8F008338D5 /* EraValidatorInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EraValidatorInfo.swift; sourceTree = ""; }; @@ -7730,6 +7736,7 @@ 84452F7225D5E2B300F47EC5 /* runtime-default.json */, 84452F7325D5E2B300F47EC5 /* runtime-kusama.json */, 8438C45A2655AC2600047E3F /* runtime-rococo.json */, + 84F1D67229069FFB0050F4E3 /* governanceDApps.json */, ); path = Resources; sourceTree = ""; @@ -7933,6 +7940,7 @@ 8455AB4928F80D9300974E88 /* ReferendumTrackType.swift */, 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */, 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */, + 848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */, ); path = ViewModel; sourceTree = ""; @@ -11439,6 +11447,7 @@ 8427495228FEB8C800B2B70B /* ReferendumNewVote.swift */, 84880C4329026C3E00CADB06 /* ReferendumDelegatingLocal.swift */, 84880C452902781E00CADB06 /* ReferendumVotingLocal.swift */, + 84F1D67029068F810050F4E3 /* GovernanceDApp.swift */, ); path = Model; sourceTree = ""; @@ -14000,6 +14009,7 @@ 84D8F16724D81CB100AF43E9 /* TitleWithSubtitleTableViewCell.xib in Resources */, 84452F7625D5E2B300F47EC5 /* runtime-default.json in Resources */, 848A837F274BB03F004493DD /* PublicSans-SemiBold.otf in Resources */, + 84F1D67329069FFB0050F4E3 /* governanceDApps.json in Resources */, 8409C2662522110F0049B5C8 /* WalletAmountView.xib in Resources */, AEF5058B261EF27B0098574D /* PurchaseProviderPickerTableViewCell.xib in Resources */, 849013B524A80986008F705E /* Assets.xcassets in Resources */, @@ -14462,6 +14472,7 @@ 842876A524AE049B00D91AD8 /* SelectableTitleListViewModel.swift in Sources */, 847C96302553426D002D288F /* ExportGenericViewModel.swift in Sources */, 84906FEC28AFD23B0049B57D /* LoadableStackActionCell.swift in Sources */, + 8487010A2907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift in Sources */, AEF73FB525DBA24300407D41 /* PhishingCheckExecutor.swift in Sources */, AEE5FB1826457AC1002B8FDC /* StakingRewardDestSetupViewController.swift in Sources */, 846AF8462525C93A00868F37 /* BalanceContext.swift in Sources */, @@ -16690,6 +16701,7 @@ 840B3D672899BFD200DA1DA9 /* QRScannerViewSettings.swift in Sources */, 577918C3D4AA22D887F605B5 /* ParaStkStakeSetupPresenter.swift in Sources */, 7050A26051FE62DB06B695F1 /* ParaStkStakeSetupInteractor.swift in Sources */, + 84F1D67129068F810050F4E3 /* GovernanceDApp.swift in Sources */, 0CD1F4D100ED82D137AB9834 /* ParaStkStakeSetupViewController.swift in Sources */, D9ECCCCF1449EFAFD0FA886E /* ParaStkStakeSetupViewLayout.swift in Sources */, A714CEAF7A86292E8D679056 /* ParaStkStakeSetupViewFactory.swift in Sources */, diff --git a/novawallet/Assets.xcassets/imageDapps/Contents.json b/novawallet/Assets.xcassets/imageDapps/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/novawallet/Assets.xcassets/imageDapps/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/Contents.json b/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/Contents.json new file mode 100644 index 0000000000..51687de363 --- /dev/null +++ b/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "imageDAppPolkassembly.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/imageDAppPolkassembly.pdf b/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/imageDAppPolkassembly.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e42d801d0f4d590169b8bfaaa484e3853d46ef60 GIT binary patch literal 4669 zcmd^@O^+Kz5QgvbEBX=%4r%xIhZIF3pF)5LyBv@r4vsS<3%ho(9hC6vd8%hTWA84? zE?4G|jH{=+tKWL-t?GU7>e-8jR_Cs>%Bano-#euqJyMIGKY!@e;+G%a{NAtj*mxG- z_v?52_sa3%*=TyX-F*CTG@<<-#@d`=;yLSWm+Re!<+fk1KA(&~empL9{_)MeZTe!f zy&7$2{ciJdyXtqc#q{NqC!0^|wKCeYXMXYNV4B~4WhrLv_S=4W)h(X&e_gElvzJfQ z)AQqBt6leJXAje-r5{dj)0oXV8*g1yF6fj>Hdd{!I-^T1#@E>!qeCviTeVxQyP$I@ zse+xhx%yhwRTp)%F_@s7PA&&;)Me*&O~$*Ry!JMSn3dHvMpvR(inWP29o%%f1Q%^q zE4I%zyHFVPK44}or%g05$b?ig>#{^hNnFPwYk76kuT}TH`>k7dKiwG+qoWJK232+S zIfo#4On5Qs=baujK>K;ypFZx7?e#qGT0{B5`$05GFWT`2RVKc z1d9YBJ2^gavfflvI8aTl0ARz-HULvi0caSCuDU~rEOG0SwkZ^Xl$cBs5+;Ch#G!()%U}V)L$r-dNjn#vaeSAdV{Hsg z#W(sEpo_!^3~l9`piQu>(TF)_DVVsFunE8>#Oec~w8m9a0mXQ4S!?8WQMWjDZ)Rp) zvoARlhLCK^W=PbW3i)=}%J4#HJ-I1~Y8^iLkgFPVKSmIltxzG8go$GmopSWf3q1xK z%&8=|1%P5qw1uJIN+_1xh;Y#00=YUu0)bu0r4G63Q-&2zdlwB^Qgo=+!MWLw*^Als zA3*T|u*tlj36>{kzARsp%R*z9NC{EA@fa|tR+ADyI!Nvbo_47sO<0omB@IbyOh_D` z=qKlc*osXC-iTBoUlk>l%t>UjVCq~Z@%bDftPSPCGWoD#-uM-wTta4}08fiEz7Z%! z$+$$Ea=~ZtLuVtZvqF507$Ge)szY>#D5Me)RK7Gd#bY@yB2EUKn$CUX$9*LeT5#UP zF_E=glJ$4cOaud|tmL&tJ&lkMW}=_b#hO8^2w;+6xF21v1OSejWEvxD&L#&e(Wih) z9i5|^5a9m`)lL#r0lSnG+F}v-d_q$Zd zMOJ9@&~We2XLQ75_$f(7SpjN;upRP8G@j_o38)03*$1kU zshp|!5-AQsG!KKMUcsgqq^e#DhXgqXrm!}niHx?IE9+V-9f7*d!T$gaRhz&_8MHYi z^5QN@%a@tDJf7Bwl98jRAC=WYL2^?%hAEH9K&b$eC7@o(g%i=rI(TR(^WwlL%D$oC zi2euEwvzu8UpsV0q2q{1CC0<>Trk&EzClyI~hc`?}t zn}Nhqx9J{ebJ)C=M6ng*DLzpe4$&7v+uEb+P~5w|!gWhh;VR|LWGVEg^hEop>})ID zTpaqoR>o|Om6K+`%q?dnf1{^S%CIk_Alf5E7ex>v(lthA1Qf@)*3;x*qLagt-}E0- zM1`7Dv}n0XF~ob&Q_884!b(8`jG{d{)BLcWo@%VHr>@Ps?E3ZFv1jH@?ggFn{lf); zZZyjW%?!?WyEmXX|L1$d6sGB=W$>7LlW}^HW@P#?-)HEOZ@J}=QImC=bUDwz%{I@N zQ{k4dOW4M+dpAWLnLLX6cu#B>!Cxri66yKA_WaZS<@tWO@7wru+x|QMVY&OGy$x4Q z`FV0NobQjPZ;O{oC^z0fPseWjT5$FJ=JLb)<(HQ}TrY2|A%^ijJe}mEjQx% zNUxUf`qA)1|Mp^e-@CP}G+)z&7KgtLJl(AK{hA#GfrIgt{0U&MxPvv*5l&(nP9T4O z`0nB@t|~dfnL2pm;2@A=H2PsPuu>tPCA@! zNKE-xr5I_*v5${zAdezL+vBa}^5U}Jb^`CW&j9zU-R7$QT77l#_Ui%S#o1;9z5-v1*W&!*?_RI~+}(b; R-8Xc&jhF7hgXcfK_y_KJ#%urp literal 0 HcmV?d00001 diff --git a/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/Contents.json b/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/Contents.json new file mode 100644 index 0000000000..3b6842cccd --- /dev/null +++ b/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "imageDAppSubsquare.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/imageDAppSubsquare.pdf b/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/imageDAppSubsquare.pdf new file mode 100644 index 0000000000000000000000000000000000000000..07da841801564f3d10708023973e0f24e69f85e1 GIT binary patch literal 1328 zcmb7EO>fgc5WVlOm`kJ2Be)(%6Ql^DLFdlZ3;*n)*$V+1A~K35+b3a zx-L{rLZ`{L>|sJda*R|?8WN#7YN?Hj*(jCVYZ&!PE}Yd$5^w6bkXj+}9zsuqjjS=- z{VP_o&;M;IB6r$a=MJtaVI3u>>KyqbVYr2MSfj9!QI&FLo-R!xBs~7nX=GSkM$}v5a%%K=;l?~hLSSIA?(3r zUK0kogC?UIp<#rR_r;o|LaZQzKF_>*q_g-;e?!QG$s94o0-GV>Sol0|^KG>`KKfLL zdnUlL!_3EDFq&oo2<{dN*zcemAW1so8X@Y|Q^?W#lPGWL;*JiYh~JA2YU{k%hML9O xd$%Av&YEf$&f%R{o4xsT^A~D|A$ { + LocalizableResource { locale in + let format = DateFormatter.dateFormat(fromTemplate: "ddMMMyyyyHHmmss", options: 0, locale: locale) + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = format + dateFormatter.locale = locale + return dateFormatter + } + } } extension DateComponentsFormatter { diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceDApp.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceDApp.swift new file mode 100644 index 0000000000..dfad823668 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceDApp.swift @@ -0,0 +1,24 @@ +import Foundation +import SoraFoundation + +struct GovernanceDApp: Codable { + struct Params: Codable { + let network: String + let index: ReferendumIdLocal + } + + let name: String + let subtitle: String + let icon: URL + let urlTemplate: String + + func url(for chain: ChainModel, referendumIndex: ReferendumIdLocal) throws -> URL { + // TODO: move to chain.json to make to reliable + let params = Params( + network: chain.name.lowercased(), + index: referendumIndex + ) + + return try EndpointBuilder(urlTemplate: urlTemplate).buildURL(with: params) + } +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 9204c2b41d..719816f2e4 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -99,6 +99,7 @@ enum ReferendumStateLocal { let track: GovernanceTrackLocal let proposal: SupportPallet.Bounded> let voting: Voting + let submitted: BlockNumber let since: BlockNumber let period: Moment let confirmationUntil: BlockNumber? diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index 8261bb3fc7..6eb5dee6e2 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -34,6 +34,7 @@ final class Gov2LocalMappingFactory { track: localTrack, proposal: status.proposal, voting: .supportAndVotes(model: votes), + submitted: status.submitted, since: deciding.since, period: track.decisionPeriod, confirmationUntil: deciding.confirming diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift index 1aacb619fd..20f09d1778 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInteractorError.swift @@ -9,4 +9,5 @@ enum ReferendumDetailsInteractorError: Error { case priceFailed(_ internalError: Error) case blockNumberFailed(_ internalError: Error) case blockTimeFailed(_ internalError: Error) + case dAppsFailed(_ internalError: Error) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 39f548ed94..a9472aa448 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -19,6 +19,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol let referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol + let dAppsRepository: JsonFileRepository<[GovernanceDApp]> let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? @@ -28,6 +29,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { private var identitiesCancellable: CancellableCall? private var actionDetailsCancellable: CancellableCall? private var blockTimeCancellable: CancellableCall? + private var dAppsCancellable: CancellableCall? init( referendum: ReferendumLocal, @@ -42,6 +44,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol, referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, + dAppsRepository: JsonFileRepository<[GovernanceDApp]>, currencyManager: CurrencyManagerProtocol, operationQueue: OperationQueue ) { @@ -57,6 +60,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { self.blockTimeService = blockTimeService self.govMetadataLocalSubscriptionFactory = govMetadataLocalSubscriptionFactory self.referendumsSubscriptionFactory = referendumsSubscriptionFactory + self.dAppsRepository = dAppsRepository self.operationQueue = operationQueue self.currencyManager = currencyManager } @@ -65,6 +69,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { clear(cancellable: &identitiesCancellable) clear(cancellable: &actionDetailsCancellable) clear(cancellable: &blockTimeCancellable) + clear(cancellable: &dAppsCancellable) referendumsSubscriptionFactory.unsubscribeFromReferendum(self, referendumIndex: referendum.index) referendumsSubscriptionFactory.unsubscribeFromAccountVotes(self, accountId: selectedAccount.accountId) @@ -111,6 +116,36 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { } } + private func provideDApps() { + clear(cancellable: &dAppsCancellable) + + let wrapper = dAppsRepository.fetchOperationWrapper( + by: R.file.governanceDAppsJson(), + defaultValue: [] + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard self?.dAppsCancellable === wrapper else { + return + } + + self?.dAppsCancellable = nil + + do { + let dApps = try wrapper.targetOperation.extractNoCancellableResultData() + self?.presenter?.didReceiveDApps(dApps) + } catch { + self?.presenter?.didReceiveError(.dAppsFailed(error)) + } + } + } + + dAppsCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } + private func provideIdentities() { clear(cancellable: &identitiesCancellable) @@ -241,6 +276,11 @@ extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol makeSubscriptions() updateActionDetails() provideIdentities() + provideDApps() + } + + func refreshDApps() { + provideDApps() } func refreshBlockTime() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 577e9425dd..22004127d2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -12,6 +12,7 @@ final class ReferendumDetailsPresenter { let referendumFormatter: LocalizableResource let referendumViewModelFactory: ReferendumsModelFactoryProtocol let referendumStringsFactory: ReferendumDisplayStringFactoryProtocol + let referendumTimelineViewModelFactory: ReferendumTimelineViewModelFactoryProtocol let chain: ChainModel let logger: LoggerProtocol @@ -24,10 +25,12 @@ final class ReferendumDetailsPresenter { private var price: PriceData? private var blockNumber: BlockNumber? private var blockTime: BlockTime? + private var dApps: [GovernanceDApp]? private lazy var iconGenerator = PolkadotIconGenerator() init( + referendum: ReferendumLocal, chain: ChainModel, interactor: ReferendumDetailsInteractorInputProtocol, wireframe: ReferendumDetailsWireframeProtocol, @@ -35,7 +38,7 @@ final class ReferendumDetailsPresenter { balanceViewModelFactory: BalanceViewModelFactoryProtocol, referendumFormatter: LocalizableResource, referendumStringsFactory: ReferendumDisplayStringFactoryProtocol, - referendum: ReferendumLocal, + referendumTimelineViewModelFactory: ReferendumTimelineViewModelFactoryProtocol, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol ) { @@ -45,6 +48,7 @@ final class ReferendumDetailsPresenter { self.referendumStringsFactory = referendumStringsFactory self.balanceViewModelFactory = balanceViewModelFactory self.referendumFormatter = referendumFormatter + self.referendumTimelineViewModelFactory = referendumTimelineViewModelFactory self.referendum = referendum self.chain = chain self.logger = logger @@ -195,12 +199,50 @@ final class ReferendumDetailsPresenter { view?.didReceive(votingDetails: viewModel) } + private func provideDAppViewModel() { + guard let dApps = dApps else { + view?.didReceive(dAppModels: nil) + return + } + + let viewModels = dApps.map { + ReferendumDAppView.Model( + icon: RemoteImageViewModel(url: $0.icon), + title: $0.name, + subtitle: $0.subtitle + ) + } + + view?.didReceive(dAppModels: viewModels) + } + + private func provideTimelineViewModel() { + guard + let blockNumber = blockNumber, + let blockTime = blockTime else { + view?.didReceive(timelineModel: nil) + return + } + + let timeline = referendumTimelineViewModelFactory.createTimelineViewModel( + for: referendum, + metadata: referendumMetadata, + currentBlock: blockNumber, + blockDuration: blockTime, + locale: selectedLocale + ) + + view?.didReceive(timelineModel: timeline) + } + private func updateView() { provideReferendumInfoViewModel() provideTitleViewModel() provideRequestedAmount() provideYourVote() provideVotingDetails() + provideDAppViewModel() + provideTimelineViewModel() } } @@ -259,13 +301,23 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol func didReceiveBlockNumber(_ blockNumber: BlockNumber) { self.blockNumber = blockNumber + interactor.refreshBlockTime() + provideVotingDetails() + provideTimelineViewModel() } func didReceiveBlockTime(_ blockTime: BlockTime) { self.blockTime = blockTime provideVotingDetails() + provideTimelineViewModel() + } + + func didReceiveDApps(_ dApps: [GovernanceDApp]) { + self.dApps = dApps + + provideDAppViewModel() } func didReceiveError(_ error: ReferendumDetailsInteractorError) { @@ -288,6 +340,10 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in self?.interactor.refreshBlockTime() } + case .dAppsFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refreshDApps() + } } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index feb5b9f936..df776fa734 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -1,7 +1,7 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { func didReceive(votingDetails: ReferendumVotingStatusDetailsView.Model) - func didReceive(title: String, dAppModels: [ReferendumDAppView.Model]) - func didReceive(title: String, timelineModel: ReferendumTimelineView.Model?) + func didReceive(dAppModels: [ReferendumDAppView.Model]?) + func didReceive(timelineModel: [ReferendumTimelineView.Model]?) func didReceive(titleModel: ReferendumDetailsTitleView.Model) func didReceive(yourVoteModel: YourVoteRow.Model?) func didReceive(requestedAmount: RequestedAmountRow.Model?) @@ -18,6 +18,7 @@ protocol ReferendumDetailsInteractorInputProtocol: AnyObject { func refreshBlockTime() func refreshActionDetails() func refreshIdentities() + func refreshDApps() func remakeSubscriptions() } @@ -30,6 +31,7 @@ protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { func didReceivePrice(_ price: PriceData?) func didReceiveBlockNumber(_ blockNumber: BlockNumber) func didReceiveBlockTime(_ blockTime: BlockTime) + func didReceiveDApps(_ dApps: [GovernanceDApp]) func didReceiveError(_ error: ReferendumDetailsInteractorError) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 98af64939e..b6e41cba0a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -1,13 +1,20 @@ import UIKit import SubstrateSdk +import SoraFoundation final class ReferendumDetailsViewController: UIViewController, ViewHolder { typealias RootViewType = ReferendumDetailsViewLayout let presenter: ReferendumDetailsPresenterProtocol + let localizationManager: LocalizationManagerProtocol - init(presenter: ReferendumDetailsPresenterProtocol) { + init( + presenter: ReferendumDetailsPresenterProtocol, + localizationManager: LocalizationManagerProtocol + ) { self.presenter = presenter + self.localizationManager = localizationManager + super.init(nibName: nil, bundle: nil) } @@ -39,101 +46,6 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { @objc private func actionVote() { presenter.vote() } - - private func setSamples() { - let status = ReferendumVotingStatusView.Model( - status: .init(name: "PASSING", kind: .positive), - time: .init(titleIcon: .init(title: "Approve in 03:59:59", icon: R.image.iconFire()), isUrgent: true), - title: "Voting status" - ) - let votingProgress = VotingProgressView.Model( - support: .init(title: "Threshold reached", icon: R.image.iconCheckmark()?.withTintColor(R.color.colorGreen15CF37()!)), - approval: .init( - passThreshold: 0.5, - ayeProgress: 0.9, - ayeMessage: "Aye: 99.9%", - passMessage: "To pass: 50%", - nayMessage: "Nay: 0.1%" - ) - ) - didReceive(votingDetails: .init( - status: status, - votingProgress: votingProgress, - aye: .init( - title: "Aye", - votes: "25,354.16 votes", - tokens: "16,492 KSM" - ), - nay: .init( - title: "Nay", - votes: "1.5 votes", - tokens: "149 KSM" - ), - buttonText: "Vote" - )) - - let iconUrl = URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/chains/white/Polkadot.svg")! - didReceive( - title: "Use Nova DApp browser", - dAppModels: [ - .init( - icon: RemoteImageViewModel(url: iconUrl), - title: "Polkassembly", - subtitle: "Comment and react" - ) - ] - ) - - let metaAccount = MetaAccountModel( - metaId: UUID().uuidString, - name: UUID().uuidString, - substrateAccountId: Data.random(of: 32)!, - substrateCryptoType: 0, - substratePublicKey: Data.random(of: 32)!, - ethereumAddress: Data.random(of: 20)!, - ethereumPublicKey: Data.random(of: 32)!, - chainAccounts: [], - type: .secrets - ) - - let optIcon = metaAccount.walletIdenticonData().flatMap { try? PolkadotIconGenerator().generateFromAccountId($0) } - let iconViewModel = optIcon.map { DrawableIconViewModel(icon: $0) } - - didReceive(trackTagsModel: .init( - titleIcon: .init(title: "main agenda".uppercased(), icon: nil), - referendumNumber: "224" - )) - didReceive(titleModel: .init( - accountIcon: iconViewModel, - accountName: "RTTI-5220", - title: "Polkadot and Kusama participation in the 10th Pais Digital Chile Summit.", - description: "The Sovereign Nature Initiative transfers, Governance, Sovereign Nature Initiative (SNI) is a non-profit foundation that has" + - "brought together multiple partners and engineers from the лоалыво одыо лоаыдвлоадо", - buttonText: "Read more" - ) - ) - - didReceive( - title: "Timeline", - timelineModel: .init(title: "Timeline", statuses: [ - .init(title: "One", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), - .init(title: "Two", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false), - .init(title: "Three", subtitle: .date("Sept 1, 2022 04:44:31"), isLast: false) - ]) - ) - - rootView.fullDetailsView.bind(title: "Full details") - - didReceive(yourVoteModel: .init( - vote: .init(title: "AYE", description: "Your vote", style: .ayeInverse), - amount: .init(topValue: "30 votes", bottomValue: "10 KSM × 3x") - )) - - didReceive(requestedAmount: .init( - title: "Requested amount", - amount: .init(topValue: "1,000 KSM", bottomValue: "$38,230") - )) - } } extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { @@ -141,12 +53,12 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { rootView.votingDetailsRow.bind(viewModel: votingDetails) } - func didReceive(title: String, dAppModels: [ReferendumDAppView.Model]) { - rootView.setDApps(title: title, models: dAppModels) + func didReceive(dAppModels: [ReferendumDAppView.Model]?) { + rootView.setDApps(models: dAppModels, locale: localizationManager.selectedLocale) } - func didReceive(title: String, timelineModel: ReferendumTimelineView.Model?) { - rootView.setTimeline(title: title, model: timelineModel) + func didReceive(timelineModel: [ReferendumTimelineView.Model]?) { + rootView.setTimeline(model: timelineModel, locale: localizationManager.selectedLocale) } func didReceive(titleModel: ReferendumDetailsTitleView.Model) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 7d88e96584..6154a62e83 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -14,7 +14,9 @@ struct ReferendumDetailsViewFactory { for: referendum, currencyManager: currencyManager, state: state - ) else { + ), + let chain = state.settings.value, + let assetInfo = chain.utilityAssetDisplayInfo() else { return nil } @@ -22,16 +24,45 @@ struct ReferendumDetailsViewFactory { let localizationManager = LocalizationManager.shared + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: assetInfo, + priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) + ) + + let statusViewModelFactory = ReferendumStatusViewModelFactory() + + let indexFormatter = NumberFormatter.index.localizableResource() + let referendumViewModelFactory = ReferendumsModelFactory( + statusViewModelFactory: statusViewModelFactory, + assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), + percentFormatter: NumberFormatter.percentHalfEven.localizableResource(), + indexFormatter: indexFormatter + ) + + let referendumStringFactory = ReferendumDisplayStringFactory() + let timelineViewModelFactory = ReferendumTimelineViewModelFactory( + statusViewModelFactory: statusViewModelFactory, + timeFormatter: DateFormatter.shortDateAndTime + ) + let presenter = ReferendumDetailsPresenter( + referendum: referendum, + chain: chain, interactor: interactor, wireframe: wireframe, - referendum: referendum, - chain: state.settings.value, + referendumViewModelFactory: referendumViewModelFactory, + balanceViewModelFactory: balanceViewModelFactory, + referendumFormatter: indexFormatter, + referendumStringsFactory: referendumStringFactory, + referendumTimelineViewModelFactory: timelineViewModelFactory, localizationManager: localizationManager, logger: Logger.shared ) - let view = ReferendumDetailsViewController(presenter: presenter) + let view = ReferendumDetailsViewController( + presenter: presenter, + localizationManager: localizationManager + ) presenter.view = view interactor.presenter = presenter @@ -76,6 +107,8 @@ struct ReferendumDetailsViewFactory { emptyIdentitiesWhenNoStorage: true ) + let dAppsRepository = JsonFileRepository<[GovernanceDApp]>() + return ReferendumDetailsInteractor( referendum: referendum, selectedAccount: selectedAccount, @@ -89,6 +122,7 @@ struct ReferendumDetailsViewFactory { generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, govMetadataLocalSubscriptionFactory: state.govMetadataLocalSubscriptionFactory, referendumsSubscriptionFactory: subscriptionFactory, + dAppsRepository: dAppsRepository, currencyManager: currencyManager, operationQueue: OperationManagerFacade.sharedDefaultQueue ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index adf5551301..5dae24b469 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -3,7 +3,7 @@ import UIKit final class ReferendumDetailsViewLayout: UIView { let containerView: ScrollableContainerView = { let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) - view.stackView.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 24, right: 16) + view.stackView.layoutMargins = UIEdgeInsets(top: 16.0, left: 16, bottom: 24, right: 16) view.stackView.isLayoutMarginsRelativeArrangement = true view.stackView.alignment = .fill return view @@ -51,53 +51,77 @@ final class ReferendumDetailsViewLayout: UIView { dAppsTableView.apply(style: .cellWithoutHighlighting) } - func setTimeline(title: String, model: ReferendumTimelineView.Model?) { + func setTimeline(model: [ReferendumTimelineView.Model]?, locale: Locale) { timelineTableView.clear() - guard let model = model else { - return + + if let model = model { + timelineTableView.isHidden = false + + let title = R.string.localizable.govReferendumDetailsTimelineTitle( + preferredLanguages: locale.rLanguages + ) + let headerView = createHeader(with: title) + let timelineRow = TimelineRow(frame: .zero) + timelineRow.bind(viewModel: model) + timelineTableView.stackView.addArrangedSubview(headerView) + timelineTableView.stackView.addArrangedSubview(timelineRow) + } else { + timelineTableView.isHidden = true } - let headerView = createHeader(with: title) - let timelineRow = TimelineRow(frame: .zero) - timelineRow.bind(viewModel: model) - timelineTableView.stackView.addArrangedSubview(headerView) - timelineTableView.stackView.addArrangedSubview(timelineRow) } - func setDApps(title: String, models: [ReferendumDAppView.Model]) { + func setDApps(models: [ReferendumDAppView.Model]?, locale: Locale) { dAppsTableView.clear() - let headerView = createHeader(with: title) - dAppsTableView.stackView.addArrangedSubview(headerView) - for model in models { - let dAppView = ReferendumDAppCellView(frame: .zero) - dAppView.rowContentView.bind(viewModel: model) - dAppsTableView.stackView.addArrangedSubview(dAppView) + if let models = models { + dAppsTableView.isHidden = false + + let title = R.string.localizable.commonUseDapp( + preferredLanguages: locale.rLanguages + ) + + let headerView = createHeader(with: title) + dAppsTableView.stackView.addArrangedSubview(headerView) + + for model in models { + let dAppView = ReferendumDAppCellView(frame: .zero) + dAppView.rowContentView.bind(viewModel: model) + dAppsTableView.stackView.addArrangedSubview(dAppView) + } + } else { + dAppsTableView.isHidden = true } } func setYourVote(model: YourVoteRow.Model?) { guard let yourVoteViewModel = model else { - yourVoteRow.map(containerView.stackView.removeArrangedSubview) + yourVoteRow?.removeFromSuperview() + yourVoteRow = nil return } + if yourVoteRow == nil { let yourVoteView = YourVoteRow(frame: .zero) - containerView.stackView.addArrangedSubview(yourVoteView) + containerView.stackView.insertArranged(view: yourVoteView, before: votingDetailsRow) yourVoteRow = yourVoteView } + yourVoteRow?.bind(viewModel: yourVoteViewModel) } func setRequestedAmount(model: RequestedAmountRow.Model?) { guard let requestedAmountViewModel = model else { - requestedAmountRow.map(containerView.stackView.removeArrangedSubview) + requestedAmountRow?.removeFromSuperview() + requestedAmountRow = nil return } + if requestedAmountRow == nil { let requestedAmountView = RequestedAmountRow(frame: .zero) - containerView.stackView.addArrangedSubview(requestedAmountView) + containerView.stackView.insertArranged(view: requestedAmountView, after: titleView) requestedAmountRow = requestedAmountView } + requestedAmountRow?.bind(viewModel: requestedAmountViewModel) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift index c70484dc47..7641997906 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift @@ -35,7 +35,7 @@ final class ReferendumTimelineView: UIView { } } - private func updateStatuses(model: Model) { + private func updateStatuses(model: [Model]) { let statusViews = statusViews(from: model) statusesContentView.arrangedSubviews.forEach { statusesContentView.removeArrangedSubview($0) @@ -48,8 +48,8 @@ final class ReferendumTimelineView: UIView { } } - private func statusViews(from model: Model) -> [(view: BaselinedView, status: Model.Status)] { - model.statuses.map { status in + private func statusViews(from model: [Model]) -> [(view: BaselinedView, status: Model)] { + model.map { status in switch status.subtitle { case let .date(date): let view = MultiValueView() @@ -76,21 +76,16 @@ final class ReferendumTimelineView: UIView { extension ReferendumTimelineView: BindableView { struct Model { let title: String - let statuses: [Status] - - struct Status { - let title: String - let subtitle: StatusSubtitle? - let isLast: Bool - } + let subtitle: StatusSubtitle? + let isLast: Bool + } - enum StatusSubtitle { - case date(String) - case interval(TitleIconViewModel) - } + enum StatusSubtitle { + case date(String) + case interval(TitleIconViewModel) } - func bind(viewModel: Model) { + func bind(viewModel: [Model]) { updateStatuses(model: viewModel) dotsView.setNeedsDisplay() dotsView.setNeedsLayout() diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift new file mode 100644 index 0000000000..cc62e4d6c2 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift @@ -0,0 +1,322 @@ +import Foundation +import SoraFoundation + +protocol ReferendumTimelineViewModelFactoryProtocol { + func createTimelineViewModel( + for referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + currentBlock: BlockNumber, + blockDuration: UInt64, + locale: Locale + ) -> [ReferendumTimelineView.Model]? +} + +final class ReferendumTimelineViewModelFactory { + let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol + let timeFormatter: LocalizableResource + + init( + statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol, + timeFormatter: LocalizableResource + ) { + self.statusViewModelFactory = statusViewModelFactory + self.timeFormatter = timeFormatter + } + + private func createPreviousTime( + atBlock: BlockNumber, + currentBlock: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> String? { + let date: Date + + if atBlock < currentBlock { + let timeInterval = atBlock.secondsTo(block: currentBlock, blockDuration: blockTime) + + date = Date().addingTimeInterval(-timeInterval) + } else { + date = Date() + } + + return timeFormatter.value(for: locale).string(from: date) + } + + private func makeCreatedViewModel( + atBlock: BlockNumber?, + currentBlock: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumTimelineView.Model { + let subtitle: ReferendumTimelineView.StatusSubtitle? + + if + let atBlock = atBlock, + let date = createPreviousTime( + atBlock: atBlock, + currentBlock: currentBlock, + blockTime: blockTime, + locale: locale + ) { + subtitle = .date(date) + } else { + subtitle = nil + } + + return .init( + title: R.string.localizable.govTimelineCreated(preferredLanguages: locale.rLanguages), + subtitle: subtitle, + isLast: false + ) + } + + private func createPreparing( + model: ReferendumStateLocal.Preparing, + referendum: ReferendumLocal, + currentBlock: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumTimelineView.Model { + let status = statusViewModelFactory.createTimeViewModel( + for: referendum, + currentBlock: currentBlock, + blockDuration: blockTime, + locale: locale + ) + + let votingTitle: String = model.inQueue ? + R.string.localizable.governanceReferendumsStatusPreparingInqueue(preferredLanguages: locale.rLanguages) : + R.string.localizable.governanceReferendumsStatusPreparing(preferredLanguages: locale.rLanguages) + + let title = R.string.localizable.govTimelineVotingFormat( + votingTitle.lowercased().firstLetterCapitalized(), + preferredLanguages: locale.rLanguages + ) + + let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel.titleIcon) } + + return .init( + title: title, + subtitle: subtitle, + isLast: false + ) + } + + private func createDeciding( + model: ReferendumStateLocal.Deciding, + referendum: ReferendumLocal, + currentBlock: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumTimelineView.Model { + let status = statusViewModelFactory.createTimeViewModel( + for: referendum, + currentBlock: currentBlock, + blockDuration: blockTime, + locale: locale + ) + + switch model.voting { + case let .supportAndVotes(votingModel): + let isPassing = votingModel.isPassing(at: currentBlock) + let votingTitle = isPassing ? + R.string.localizable.governanceReferendumsStatusPassing(preferredLanguages: locale.rLanguages) : + R.string.localizable.governanceReferendumsStatusNotPassing(preferredLanguages: locale.rLanguages) + + let title = R.string.localizable.govTimelineVotingFormat( + votingTitle.lowercased().firstLetterCapitalized(), + preferredLanguages: locale.rLanguages + ) + + let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel.titleIcon) } + + return .init( + title: title, + subtitle: subtitle, + isLast: false + ) + } + } + + private func createApprovedTitle(for locale: Locale) -> String { + let votingTitle = R.string.localizable.governanceReferendumsStatusApproved(preferredLanguages: locale.rLanguages) + + return R.string.localizable.govTimelineVotedFormat( + votingTitle.lowercased().firstLetterCapitalized(), + preferredLanguages: locale.rLanguages + ) + } + + private func createApproved( + referendum: ReferendumLocal, + currentBlock: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumTimelineView.Model { + let status = statusViewModelFactory.createTimeViewModel( + for: referendum, + currentBlock: currentBlock, + blockDuration: blockTime, + locale: locale + ) + + let title = createApprovedTitle(for: locale) + + let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel.titleIcon) } + + return .init( + title: title, + subtitle: subtitle, + isLast: false + ) + } + + private func createVotedTerminal( + status: String, + atBlock: BlockNumber, + currentBlock: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumTimelineView.Model { + let date = createPreviousTime( + atBlock: atBlock, + currentBlock: currentBlock, + blockTime: blockTime, + locale: locale + ) + + let title = R.string.localizable.govTimelineVotedFormat( + status.lowercased().firstLetterCapitalized(), + preferredLanguages: locale.rLanguages + ) + + let subtitle = date.map { ReferendumTimelineView.StatusSubtitle.date($0) } + + return .init(title: title, subtitle: subtitle, isLast: true) + } +} + +extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactoryProtocol { + func createTimelineViewModel( + for referendum: ReferendumLocal, + metadata _: ReferendumMetadataLocal?, + currentBlock: BlockNumber, + blockDuration: UInt64, + locale: Locale + ) -> [ReferendumTimelineView.Model]? { + let createdAt: BlockNumber? + + let models: [ReferendumTimelineView.Model] + + switch referendum.state { + case let .preparing(model): + createdAt = model.since + + let preparing = createPreparing( + model: model, + referendum: referendum, + currentBlock: currentBlock, + blockTime: blockDuration, + locale: locale + ) + + models = [preparing] + case let .deciding(model): + createdAt = model.submitted + + let deciding = createDeciding( + model: model, + referendum: referendum, + currentBlock: currentBlock, + blockTime: blockDuration, + locale: locale + ) + + models = [deciding] + case .approved: + createdAt = nil + + let approved = createApproved( + referendum: referendum, + currentBlock: currentBlock, + blockTime: blockDuration, + locale: locale + ) + + models = [approved] + case let .rejected(atBlock): + createdAt = nil + + let rejected = createVotedTerminal( + status: R.string.localizable.governanceReferendumsStatusRejected(preferredLanguages: locale.rLanguages), + atBlock: atBlock, + currentBlock: currentBlock, + blockTime: blockDuration, + locale: locale + ) + + models = [rejected] + case let .cancelled(atBlock): + createdAt = nil + + let cancelled = createVotedTerminal( + status: R.string.localizable.governanceReferendumsStatusCancelled(preferredLanguages: locale.rLanguages), + atBlock: atBlock, + currentBlock: currentBlock, + blockTime: blockDuration, + locale: locale + ) + + models = [cancelled] + case let .killed(atBlock): + createdAt = nil + + let killed = createVotedTerminal( + status: R.string.localizable.governanceReferendumsStatusKilled(preferredLanguages: locale.rLanguages), + atBlock: atBlock, + currentBlock: currentBlock, + blockTime: blockDuration, + locale: locale + ) + + models = [killed] + case let .timedOut(atBlock): + createdAt = nil + + let timedOut = createVotedTerminal( + status: R.string.localizable.governanceReferendumsStatusTimedOut(preferredLanguages: locale.rLanguages), + atBlock: atBlock, + currentBlock: currentBlock, + blockTime: blockDuration, + locale: locale + ) + + models = [timedOut] + case .executed: + createdAt = nil + + let approved = ReferendumTimelineView.Model( + title: createApprovedTitle(for: locale), + subtitle: nil, + isLast: false + ) + + let executed = ReferendumTimelineView.Model( + title: R.string.localizable.governanceReferendumsStatusExecuted(preferredLanguages: locale.rLanguages), + subtitle: nil, + isLast: true + ) + + models = [approved, executed] + } + + let created = makeCreatedViewModel( + atBlock: createdAt, + currentBlock: currentBlock, + blockTime: blockDuration, + locale: locale + ) + + return [created] + models + } +} diff --git a/novawallet/Resources/governanceDApps.json b/novawallet/Resources/governanceDApps.json new file mode 100644 index 0000000000..1eda9cae8a --- /dev/null +++ b/novawallet/Resources/governanceDApps.json @@ -0,0 +1,14 @@ +[ + { + "name": "Polkassembly", + "subtitle": "Comment and react", + "icon": "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/dapps/color/Polkassembly.svg", + "urlTemplate": "https://{network}.polkassembly.io/referendum/{index}" + }, + { + "name": "Subsquare", + "subtitle": "Comment and react", + "icon": "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/icons/chains/color/SubSquare.svg", + "urlTemplate": "https://{network}.subsquare.io/democracy/referendum/{index}" + } +] diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 3e57ab6468..fa5406274e 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1033,7 +1033,6 @@ "gov.vote.setup.title.format" = "Vote for %@"; "common.available.prefix" = "Available:"; "common.maximum" = "%@ maximum"; -"gov.referendum.details.dApps.title" = "Use Nova DApp browser"; "gov.referendum.details.timeline.title" = "Timeline"; "gov.your.vote" = "Your vote"; "common.amount.too.big" = "Amount is too big"; @@ -1050,3 +1049,8 @@ "gov.revote" = "Revote"; "gov.details.voting.status" = "Voting status"; "common.requested.amount" = "Requested amount"; +"common.react.comment" = "Comment and react"; +"common.use.dapp" = "Use Nova Featured websites"; +"gov.timeline.created" = "Created"; +"gov.timeline.voting.format" = "Voting: %@"; +"gov.timeline.voted.format" = "Voted: %@"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index ab5967be33..0ad3999582 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1034,7 +1034,6 @@ "gov.vote.setup.title.format" = "Голосование за %@"; "common.available.prefix" = "Доступно:"; "common.maximum" = "%@ максимум"; -"gov.referendum.details.dApps.title" = "Использовать Nova DApp браузер"; "gov.referendum.details.timeline.title" = "Статусы"; "gov.your.vote" = "Ваш голос"; "common.amount.too.big" = "Сумма слишком большая"; @@ -1051,3 +1050,8 @@ "gov.revote" = "Изменить голос"; "gov.details.voting.status" = "Статус голосования"; "common.requested.amount" = "Запрашиваемая сумма"; +"common.react.comment" = "Комментарии и реакции"; +"common.use.dapp" = "Использовать популярные вебсайты в Nova"; +"gov.timeline.created" = "Создано"; +"gov.timeline.voting.format" = "В процессе голосования: %@"; +"gov.timeline.voted.format" = "Голосование завершено: %@"; From 0d75f90852f818c2be0c0a54f144429cb04165a6 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 25 Oct 2022 11:56:27 +0500 Subject: [PATCH 094/229] fix title view --- novawallet.xcodeproj/project.pbxproj | 4 + .../Assets.xcassets/imageDapps/Contents.json | 6 - .../Contents.json | 12 -- .../imageDAppPolkassembly.pdf | Bin 4669 -> 0 bytes .../imageDAppSubsquare.imageset/Contents.json | 12 -- .../imageDAppSubsquare.pdf | Bin 1328 -> 0 bytes .../Extension/Foundation/String+Helpers.swift | 9 + .../ReferendumDetailsPresenter.swift | 48 +++-- .../ReferendumDetailsProtocols.swift | 5 +- .../ReferendumDetailsViewController.swift | 22 ++- .../ReferendumDetailsViewFactory.swift | 4 + .../ReferendumDetailsViewLayout.swift | 2 +- .../View/ReferendumDetailsTitleView.swift | 167 +++++++++++------- .../View/TrackTagsView.swift | 4 +- .../ReferendumMetadataViewModelFactory.swift | 67 +++++++ novawallet/en.lproj/Localizable.strings | 3 + novawallet/ru.lproj/Localizable.strings | 3 + 17 files changed, 253 insertions(+), 115 deletions(-) delete mode 100644 novawallet/Assets.xcassets/imageDapps/Contents.json delete mode 100644 novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/Contents.json delete mode 100644 novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/imageDAppPolkassembly.pdf delete mode 100644 novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/Contents.json delete mode 100644 novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/imageDAppSubsquare.pdf create mode 100644 novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 0f26c08989..25fb09dd24 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1252,6 +1252,7 @@ 8483B15D28FA79620048B295 /* ReferendumDisplayStringFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */; }; 8485D924277E16C400767243 /* DAppBrowserScriptHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */; }; 8487010A2907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */; }; + 8487010C2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8487010B2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift */; }; 84873AFF26028E2B000A83EE /* StakingStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */; }; 84873B0426029B75000A83EE /* StakingEstimationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */; }; 84873B0926029CBD000A83EE /* StakingStateViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873B0826029CBD000A83EE /* StakingStateViewModelFactory.swift */; }; @@ -4169,6 +4170,7 @@ 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDisplayStringFactory.swift; sourceTree = ""; }; 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserScriptHandler.swift; sourceTree = ""; }; 848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumTimelineViewModelFactory.swift; sourceTree = ""; }; + 8487010B2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumMetadataViewModelFactory.swift; sourceTree = ""; }; 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingStateMachine.swift; sourceTree = ""; }; 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingEstimationViewModel.swift; sourceTree = ""; }; 84873B0826029CBD000A83EE /* StakingStateViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingStateViewModelFactory.swift; sourceTree = ""; }; @@ -7941,6 +7943,7 @@ 8483B15C28FA79620048B295 /* ReferendumDisplayStringFactory.swift */, 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */, 848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */, + 8487010B2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift */, ); path = ViewModel; sourceTree = ""; @@ -14743,6 +14746,7 @@ 88421057289BBA8D00306F2C /* CurrencyProtocols.swift in Sources */, 842BDB28278C4CE500AB4B5A /* DAppBrowserWaitingAuthState.swift in Sources */, 845AADA32902D1EB00B5AE96 /* StackTitleValueDiffCell.swift in Sources */, + 8487010C2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift in Sources */, 848DAF042822B7FE00D56F55 /* ParachainStakingCollatorService+Fetch.swift in Sources */, 840689FC26321F2700A017B1 /* StorageQuery.swift in Sources */, 8423ADD026B2C38600057EDD /* ImportantFlowViewFactory.swift in Sources */, diff --git a/novawallet/Assets.xcassets/imageDapps/Contents.json b/novawallet/Assets.xcassets/imageDapps/Contents.json deleted file mode 100644 index 73c00596a7..0000000000 --- a/novawallet/Assets.xcassets/imageDapps/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/Contents.json b/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/Contents.json deleted file mode 100644 index 51687de363..0000000000 --- a/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "imageDAppPolkassembly.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/imageDAppPolkassembly.pdf b/novawallet/Assets.xcassets/imageDapps/imageDAppPolkassembly.imageset/imageDAppPolkassembly.pdf deleted file mode 100644 index e42d801d0f4d590169b8bfaaa484e3853d46ef60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4669 zcmd^@O^+Kz5QgvbEBX=%4r%xIhZIF3pF)5LyBv@r4vsS<3%ho(9hC6vd8%hTWA84? zE?4G|jH{=+tKWL-t?GU7>e-8jR_Cs>%Bano-#euqJyMIGKY!@e;+G%a{NAtj*mxG- z_v?52_sa3%*=TyX-F*CTG@<<-#@d`=;yLSWm+Re!<+fk1KA(&~empL9{_)MeZTe!f zy&7$2{ciJdyXtqc#q{NqC!0^|wKCeYXMXYNV4B~4WhrLv_S=4W)h(X&e_gElvzJfQ z)AQqBt6leJXAje-r5{dj)0oXV8*g1yF6fj>Hdd{!I-^T1#@E>!qeCviTeVxQyP$I@ zse+xhx%yhwRTp)%F_@s7PA&&;)Me*&O~$*Ry!JMSn3dHvMpvR(inWP29o%%f1Q%^q zE4I%zyHFVPK44}or%g05$b?ig>#{^hNnFPwYk76kuT}TH`>k7dKiwG+qoWJK232+S zIfo#4On5Qs=baujK>K;ypFZx7?e#qGT0{B5`$05GFWT`2RVKc z1d9YBJ2^gavfflvI8aTl0ARz-HULvi0caSCuDU~rEOG0SwkZ^Xl$cBs5+;Ch#G!()%U}V)L$r-dNjn#vaeSAdV{Hsg z#W(sEpo_!^3~l9`piQu>(TF)_DVVsFunE8>#Oec~w8m9a0mXQ4S!?8WQMWjDZ)Rp) zvoARlhLCK^W=PbW3i)=}%J4#HJ-I1~Y8^iLkgFPVKSmIltxzG8go$GmopSWf3q1xK z%&8=|1%P5qw1uJIN+_1xh;Y#00=YUu0)bu0r4G63Q-&2zdlwB^Qgo=+!MWLw*^Als zA3*T|u*tlj36>{kzARsp%R*z9NC{EA@fa|tR+ADyI!Nvbo_47sO<0omB@IbyOh_D` z=qKlc*osXC-iTBoUlk>l%t>UjVCq~Z@%bDftPSPCGWoD#-uM-wTta4}08fiEz7Z%! z$+$$Ea=~ZtLuVtZvqF507$Ge)szY>#D5Me)RK7Gd#bY@yB2EUKn$CUX$9*LeT5#UP zF_E=glJ$4cOaud|tmL&tJ&lkMW}=_b#hO8^2w;+6xF21v1OSejWEvxD&L#&e(Wih) z9i5|^5a9m`)lL#r0lSnG+F}v-d_q$Zd zMOJ9@&~We2XLQ75_$f(7SpjN;upRP8G@j_o38)03*$1kU zshp|!5-AQsG!KKMUcsgqq^e#DhXgqXrm!}niHx?IE9+V-9f7*d!T$gaRhz&_8MHYi z^5QN@%a@tDJf7Bwl98jRAC=WYL2^?%hAEH9K&b$eC7@o(g%i=rI(TR(^WwlL%D$oC zi2euEwvzu8UpsV0q2q{1CC0<>Trk&EzClyI~hc`?}t zn}Nhqx9J{ebJ)C=M6ng*DLzpe4$&7v+uEb+P~5w|!gWhh;VR|LWGVEg^hEop>})ID zTpaqoR>o|Om6K+`%q?dnf1{^S%CIk_Alf5E7ex>v(lthA1Qf@)*3;x*qLagt-}E0- zM1`7Dv}n0XF~ob&Q_884!b(8`jG{d{)BLcWo@%VHr>@Ps?E3ZFv1jH@?ggFn{lf); zZZyjW%?!?WyEmXX|L1$d6sGB=W$>7LlW}^HW@P#?-)HEOZ@J}=QImC=bUDwz%{I@N zQ{k4dOW4M+dpAWLnLLX6cu#B>!Cxri66yKA_WaZS<@tWO@7wru+x|QMVY&OGy$x4Q z`FV0NobQjPZ;O{oC^z0fPseWjT5$FJ=JLb)<(HQ}TrY2|A%^ijJe}mEjQx% zNUxUf`qA)1|Mp^e-@CP}G+)z&7KgtLJl(AK{hA#GfrIgt{0U&MxPvv*5l&(nP9T4O z`0nB@t|~dfnL2pm;2@A=H2PsPuu>tPCA@! zNKE-xr5I_*v5${zAdezL+vBa}^5U}Jb^`CW&j9zU-R7$QT77l#_Ui%S#o1;9z5-v1*W&!*?_RI~+}(b; R-8Xc&jhF7hgXcfK_y_KJ#%urp diff --git a/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/Contents.json b/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/Contents.json deleted file mode 100644 index 3b6842cccd..0000000000 --- a/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "imageDAppSubsquare.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/imageDAppSubsquare.pdf b/novawallet/Assets.xcassets/imageDapps/imageDAppSubsquare.imageset/imageDAppSubsquare.pdf deleted file mode 100644 index 07da841801564f3d10708023973e0f24e69f85e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1328 zcmb7EO>fgc5WVlOm`kJ2Be)(%6Ql^DLFdlZ3;*n)*$V+1A~K35+b3a zx-L{rLZ`{L>|sJda*R|?8WN#7YN?Hj*(jCVYZ&!PE}Yd$5^w6bkXj+}9zsuqjjS=- z{VP_o&;M;IB6r$a=MJtaVI3u>>KyqbVYr2MSfj9!QI&FLo-R!xBs~7nX=GSkM$}v5a%%K=;l?~hLSSIA?(3r zUK0kogC?UIp<#rR_r;o|LaZQzKF_>*q_g-;e?!QG$s94o0-GV>Sol0|^KG>`KKfLL zdnUlL!_3EDFq&oo2<{dN*zcemAW1so8X@Y|Q^?W#lPGWL;*JiYh~JA2YU{k%hML9O xd$%Av&YEf$&f%R{o4xsT^A~D|A$ String { prefix(1).capitalized + dropFirst() } + + func convertToReadMore(after threshold: Int) -> String { + if count > threshold { + return String(prefix(threshold)) + String.readMore + } else { + return self + } + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 22004127d2..cc9f483ad4 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -13,6 +13,8 @@ final class ReferendumDetailsPresenter { let referendumViewModelFactory: ReferendumsModelFactoryProtocol let referendumStringsFactory: ReferendumDisplayStringFactoryProtocol let referendumTimelineViewModelFactory: ReferendumTimelineViewModelFactoryProtocol + let referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol + let displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol let chain: ChainModel let logger: LoggerProtocol @@ -39,6 +41,8 @@ final class ReferendumDetailsPresenter { referendumFormatter: LocalizableResource, referendumStringsFactory: ReferendumDisplayStringFactoryProtocol, referendumTimelineViewModelFactory: ReferendumTimelineViewModelFactoryProtocol, + referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol, + displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol ) { @@ -49,6 +53,8 @@ final class ReferendumDetailsPresenter { self.balanceViewModelFactory = balanceViewModelFactory self.referendumFormatter = referendumFormatter self.referendumTimelineViewModelFactory = referendumTimelineViewModelFactory + self.referendumMetadataViewModelFactory = referendumMetadataViewModelFactory + self.displayAddressViewModelFactory = displayAddressViewModelFactory self.referendum = referendum self.chain = chain self.logger = logger @@ -69,35 +75,27 @@ final class ReferendumDetailsPresenter { } private func provideTitleViewModel() { - let accountIcon: DrawableIconViewModel? - let accountDisplayName: String? + let accountViewModel: DisplayAddressViewModel? if let proposer = referendum.proposer, let identities = identities, let address = try? proposer.toAddress(using: chain.chainFormat) { - accountIcon = (try? iconGenerator.generateFromAccountId(proposer)).map { - DrawableIconViewModel(icon: $0) - } - - accountDisplayName = identities[address]?.displayName ?? address + let displayAddress = DisplayAddress(address: address, username: identities[address]?.displayName ?? "") + accountViewModel = displayAddressViewModelFactory.createViewModel(from: displayAddress) } else { - accountIcon = nil - accountDisplayName = nil + accountViewModel = nil } - let detailsLength = referendumMetadata?.details.count ?? 0 - - let shouldReadMore = detailsLength > Self.readMoreThreshold - - let viewModel = ReferendumDetailsTitleView.Model( - accountIcon: accountIcon, - accountName: accountDisplayName, - title: referendumMetadata?.name ?? "", - description: referendumMetadata?.details ?? "", - shouldReadMore: shouldReadMore + let detailsViewModel = referendumMetadataViewModelFactory.createDetailsViewModel( + for: referendum, + metadata: referendumMetadata, + readMoreThreshold: Self.readMoreThreshold, + locale: selectedLocale ) + let viewModel = ReferendumDetailsTitleView.Model(account: accountViewModel, details: detailsViewModel) + view?.didReceive(titleModel: viewModel) } @@ -256,6 +254,18 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { func vote() { wireframe.showVote(from: view, referendum: referendum) } + + func showProposerDetails() { + guard + let proposerAddress = try? referendum.proposer?.toAddress(using: chain.chainFormat), + let view = view else { + return + } + + wireframe.presentAccountOptions(from: view, address: proposerAddress, chain: chain, locale: selectedLocale) + } + + func readFullDescription() {} } extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index df776fa734..a393eafded 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -10,6 +10,8 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { protocol ReferendumDetailsPresenterProtocol: AnyObject { func setup() + func showProposerDetails() + func readFullDescription() func vote() } @@ -35,7 +37,8 @@ protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { func didReceiveError(_ error: ReferendumDetailsInteractorError) } -protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable { +protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, + AddressOptionsPresentable { func showFullDetails( from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index b6e41cba0a..0e4ecaefd6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -41,11 +41,31 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { action: #selector(actionVote), for: .touchUpInside ) + + rootView.titleView.accountContainerView.addTarget( + self, + action: #selector(actionProposer), + for: .touchUpInside + ) + + rootView.titleView.moreButton.addTarget( + self, + action: #selector(actionFullDescription), + for: .touchUpInside + ) } @objc private func actionVote() { presenter.vote() } + + @objc private func actionProposer() { + presenter.showProposerDetails() + } + + @objc private func actionFullDescription() { + presenter.readFullDescription() + } } extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { @@ -62,7 +82,7 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { } func didReceive(titleModel: ReferendumDetailsTitleView.Model) { - rootView.titleView.bind(viewModel: titleModel) + rootView.titleView.bind(viewModel: titleModel, locale: localizationManager.selectedLocale) } func didReceive(yourVoteModel: YourVoteRow.Model?) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 6154a62e83..d7d98f6c93 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -45,6 +45,8 @@ struct ReferendumDetailsViewFactory { timeFormatter: DateFormatter.shortDateAndTime ) + let metadataViewModelFactory = ReferendumMetadataViewModelFactory(indexFormatter: indexFormatter) + let presenter = ReferendumDetailsPresenter( referendum: referendum, chain: chain, @@ -55,6 +57,8 @@ struct ReferendumDetailsViewFactory { referendumFormatter: indexFormatter, referendumStringsFactory: referendumStringFactory, referendumTimelineViewModelFactory: timelineViewModelFactory, + referendumMetadataViewModelFactory: metadataViewModelFactory, + displayAddressViewModelFactory: DisplayAddressViewModelFactory(), localizationManager: localizationManager, logger: Logger.shared ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 5dae24b469..54ac95bced 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -3,7 +3,7 @@ import UIKit final class ReferendumDetailsViewLayout: UIView { let containerView: ScrollableContainerView = { let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) - view.stackView.layoutMargins = UIEdgeInsets(top: 16.0, left: 16, bottom: 24, right: 16) + view.stackView.layoutMargins = UIEdgeInsets(top: 6.0, left: 16, bottom: 24, right: 16) view.stackView.isLayoutMarginsRelativeArrangement = true view.stackView.alignment = .fill return view diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index 5ef6a77000..80484660f1 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -1,21 +1,64 @@ import UIKit +import SoraUI final class ReferendumDetailsTitleView: UIView { - let addressView = PolkadotIconDetailsView() - let infoImageView = UIImageView() + var accountIconSize: CGSize { + let size = accountContainerView.rowContentView.detailsView.iconWidth + return CGSize(width: size, height: size) + } + + var accountLabel: UILabel { accountContainerView.rowContentView.detailsView.detailsLabel } + var accountImageView: UIImageView { accountContainerView.rowContentView.detailsView.imageView } + + let accountContainerView: RowView> = .create { view in + view.roundedBackgroundView.highlightedFillColor = .clear + view.changesContentOpacityWhenHighlighted = true + view.borderView.borderType = .none + + view.preferredHeight = 36.0 + view.rowContentView.mode = .detailsIcon + view.rowContentView.iconWidth = 16.0 + view.rowContentView.spacing = 6 + view.contentInsets = UIEdgeInsets(top: 9, left: 0, bottom: 9, right: 0) + view.rowContentView.imageView.image = R.image.iconInfoFilled()?.tinted(with: R.color.colorWhite48()!) + + let addressView = view.rowContentView.detailsView + addressView.spacing = 7 + addressView.detailsLabel.numberOfLines = 1 + addressView.detailsLabel.textColor = R.color.colorTransparentText() + addressView.detailsLabel.font = .regularFootnote + addressView.iconWidth = 18.0 + } + + private var addressImageViewModel: ImageViewModelProtocol? + + let titleLabel: UILabel = .create { + $0.textColor = R.color.colorWhite() + $0.font = .boldTitle1 + $0.numberOfLines = 0 + } + let textView: UITextView = .create { + $0.textColor = R.color.colorTransparentText() + $0.font = .regularSubheadline $0.isScrollEnabled = false + $0.isEditable = false + $0.textContainerInset = .zero + $0.textContainer.lineFragmentPadding = 0 } - let moreButton: UIButton = .create { + let moreButton: RoundedButton = .create { button in + button.applyIconStyle() + let color = R.color.colorAccent()! - $0.titleLabel?.apply(style: .rowLink) - $0.setImage( - R.image.iconChevronRight()?.tinted(with: color), - for: .normal - ) - $0.setTitleColor(color, for: .normal) - $0.semanticContentAttribute = .forceRightToLeft + button.imageWithTitleView?.titleColor = color + button.imageWithTitleView?.titleFont = .regularFootnote + + button.imageWithTitleView?.iconImage = R.image.iconLinkChevron()?.tinted(with: color) + button.imageWithTitleView?.layoutType = .horizontalLabelFirst + button.contentInsets = .zero + + button.imageWithTitleView?.spacingBetweenLabelAndIcon = 4.0 } override init(frame: CGRect) { @@ -30,85 +73,85 @@ final class ReferendumDetailsTitleView: UIView { private func setupLayout() { let content = UIView.vStack( - spacing: 9, [ UIView.hStack( - spacing: 6, [ - addressView, - infoImageView, + accountContainerView, UIView() ] ), - textView, - UIView.hStack([ - moreButton, - UIView() - ]) + UIView.vStack( + spacing: 6, + [ + titleLabel, + textView, + UIView.hStack([ + moreButton, + UIView() + ]) + ] + ) ] ) + addSubview(content) content.snp.makeConstraints { $0.edges.equalToSuperview() } - textView.snp.makeConstraints { - $0.height.lessThanOrEqualTo(220) + + moreButton.snp.makeConstraints { make in + make.height.equalTo(32) } } } extension ReferendumDetailsTitleView { struct Model { - let accountIcon: DrawableIconViewModel? - let accountName: String? + let account: DisplayAddressViewModel? + let details: Details? + } + + struct Details { let title: String let description: String let shouldReadMore: Bool } - func bind(viewModel: Model) { - viewModel.accountIcon.map { - addressView.imageView.fillColor = $0.fillColor - addressView.imageView.bind(icon: $0.icon) - } - addressView.titleLabel.text = viewModel.accountName + func bind(viewModel: Model, locale: Locale) { + addressImageViewModel?.cancel(on: accountImageView) + addressImageViewModel = viewModel.account?.imageViewModel - addressView.isHidden = viewModel.accountIcon == nil && viewModel.accountName == nil + if let account = viewModel.account { + accountContainerView.isHidden = false - let titleAttributedString = NSAttributedString( - string: viewModel.title, - attributes: titleAttributes - ) - let descriptionAttributedString = NSAttributedString( - string: viewModel.description, - attributes: descriptionAttributes - ) - let referendumInfo = NSMutableAttributedString() - referendumInfo.append(titleAttributedString) - referendumInfo.append(NSAttributedString(string: "\n")) - referendumInfo.append(descriptionAttributedString) - textView.attributedText = referendumInfo + accountLabel.text = account.name ?? account.address.truncated - moreButton.isHidden = viewModel.shouldReadMore - } + account.imageViewModel?.loadImage( + on: accountImageView, + targetSize: accountIconSize, + animated: true + ) - private var titleAttributes: [NSAttributedString.Key: Any] { - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.lineBreakMode = .byWordWrapping - return [ - .font: UIFont.boldTitle1, - .foregroundColor: R.color.colorWhite()!, - .paragraphStyle: paragraphStyle - ] - } + } else { + accountContainerView.isHidden = true + } - private var descriptionAttributes: [NSAttributedString.Key: Any] { - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.lineBreakMode = .byWordWrapping - return [ - .font: UIFont.regularSubheadline, - .foregroundColor: R.color.colorWhite64()!, - .paragraphStyle: paragraphStyle - ] + if let details = viewModel.details { + titleLabel.isHidden = false + textView.isHidden = false + + titleLabel.text = details.title + textView.text = details.description + + moreButton.imageWithTitleView?.title = R.string.localizable.commonReadMore( + preferredLanguages: locale.rLanguages + ) + + moreButton.isHidden = !details.shouldReadMore + } else { + titleLabel.isHidden = true + textView.isHidden = true + moreButton.isHidden = true + } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift index 4079c93765..501b3a967f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift @@ -7,13 +7,15 @@ final class TrackTagsView: UIView { $0.iconDetailsView.detailsLabel.apply(style: .track) $0.backgroundView.apply(style: .referendum) $0.iconDetailsView.detailsLabel.numberOfLines = 1 + $0.backgroundView.cornerRadius = 8.0 } let numberLabel: BorderedLabelView = .create { $0.titleLabel.apply(style: .track) - $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) + $0.contentInsets = .init(top: 4, left: 8, bottom: 4, right: 8) $0.backgroundView.apply(style: .referendum) $0.titleLabel.numberOfLines = 1 + $0.backgroundView.cornerRadius = 8.0 } private(set) var trackIconViewModel: ImageViewModelProtocol? diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift new file mode 100644 index 0000000000..e3c6712f02 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift @@ -0,0 +1,67 @@ +import Foundation +import SoraFoundation + +protocol ReferendumMetadataViewModelFactoryProtocol { + func createTitle( + for referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + locale: Locale + ) -> String + + func createDescription( + for referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + locale: Locale + ) -> String +} + +extension ReferendumMetadataViewModelFactoryProtocol { + func createDetailsViewModel( + for referendum: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + readMoreThreshold: Int?, + locale: Locale + ) -> ReferendumDetailsTitleView.Details { + let title = createTitle(for: referendum, metadata: metadata, locale: locale) + let description = createDescription(for: referendum, metadata: metadata, locale: locale) + + if let readMoreThreshold = readMoreThreshold, description.count > readMoreThreshold { + let readMoreDescription = description.convertToReadMore(after: readMoreThreshold) + + return .init(title: title, description: readMoreDescription, shouldReadMore: true) + } else { + return .init(title: title, description: description, shouldReadMore: false) + } + } +} + +final class ReferendumMetadataViewModelFactory { + let indexFormatter: LocalizableResource + + init(indexFormatter: LocalizableResource) { + self.indexFormatter = indexFormatter + } +} + +extension ReferendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol { + func createTitle(for referendum: ReferendumLocal, metadata: ReferendumMetadataLocal?, locale: Locale) -> String { + if let title = metadata?.name, !title.isEmpty { + return title + } else { + let index = indexFormatter.value(for: locale).string(from: referendum.index as NSNumber) + + return R.string.localizable.govReferendumTitleFallback( + index ?? "", + preferredLanguages: locale.rLanguages + ) + } + } + + func createDescription(for _: ReferendumLocal, metadata: ReferendumMetadataLocal?, locale: Locale) -> String { + if let description = metadata?.details, !description.isEmpty { + return description + } else { + return R.string.localizable.govReferendumDescriptionFallback(preferredLanguages: locale.rLanguages) + } + } +} diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index fa5406274e..4e8f379104 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1054,3 +1054,6 @@ "gov.timeline.created" = "Created"; "gov.timeline.voting.format" = "Voting: %@"; "gov.timeline.voted.format" = "Voted: %@"; +"common.read.more" = "Read more"; +"gov.referendum.title.fallback" = "Referendum %@"; +"gov.referendum.description.fallback" = "Only the proposer can edit this description and the title. If you own proposer's account, visit Polkassembly and fill in information about your proposal"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 0ad3999582..90a3937ee9 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1055,3 +1055,6 @@ "gov.timeline.created" = "Создано"; "gov.timeline.voting.format" = "В процессе голосования: %@"; "gov.timeline.voted.format" = "Голосование завершено: %@"; +"common.read.more" = "Читать дальше"; +"gov.referendum.title.fallback" = "Референдум %@"; +"gov.referendum.description.fallback" = "Только создатель референдума может редактировать заголовок и описание. Если Вы владеете аккаунтом создателя референдума, то заполните информацию о референдуме на Polkassembly"; From 25657c2e456c98e2d30a16e561b4196e14c61909 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 25 Oct 2022 12:08:31 +0500 Subject: [PATCH 095/229] fix titles --- .../View/ReferendumDetailsTitleView.swift | 18 ++++++++++++------ .../ReferendumDetails/View/TrackTagsView.swift | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index 80484660f1..2a76055c46 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -47,6 +47,8 @@ final class ReferendumDetailsTitleView: UIView { $0.textContainer.lineFragmentPadding = 0 } + private var readMoreContainer: UIView? + let moreButton: RoundedButton = .create { button in button.applyIconStyle() @@ -72,6 +74,13 @@ final class ReferendumDetailsTitleView: UIView { } private func setupLayout() { + let buttonContainer = UIView.hStack([ + moreButton, + UIView() + ]) + + readMoreContainer = buttonContainer + let content = UIView.vStack( [ UIView.hStack( @@ -85,10 +94,7 @@ final class ReferendumDetailsTitleView: UIView { [ titleLabel, textView, - UIView.hStack([ - moreButton, - UIView() - ]) + buttonContainer ] ) ] @@ -147,11 +153,11 @@ extension ReferendumDetailsTitleView { preferredLanguages: locale.rLanguages ) - moreButton.isHidden = !details.shouldReadMore + readMoreContainer?.isHidden = !details.shouldReadMore } else { titleLabel.isHidden = true textView.isHidden = true - moreButton.isHidden = true + readMoreContainer?.isHidden = true } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift index 501b3a967f..c96d06a860 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift @@ -7,7 +7,7 @@ final class TrackTagsView: UIView { $0.iconDetailsView.detailsLabel.apply(style: .track) $0.backgroundView.apply(style: .referendum) $0.iconDetailsView.detailsLabel.numberOfLines = 1 - $0.backgroundView.cornerRadius = 8.0 + $0.backgroundView.cornerRadius = 7.0 } let numberLabel: BorderedLabelView = .create { @@ -15,7 +15,7 @@ final class TrackTagsView: UIView { $0.contentInsets = .init(top: 4, left: 8, bottom: 4, right: 8) $0.backgroundView.apply(style: .referendum) $0.titleLabel.numberOfLines = 1 - $0.backgroundView.cornerRadius = 8.0 + $0.backgroundView.cornerRadius = 7.0 } private(set) var trackIconViewModel: ImageViewModelProtocol? From 447b43deaeb03bcb650d6832976d697faadadc33 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 25 Oct 2022 16:10:07 +0500 Subject: [PATCH 096/229] fix voting view --- novawallet.xcodeproj/project.pbxproj | 4 + .../ReferendumDetailsPresenter.swift | 8 ++ .../ReferendumDetailsProtocols.swift | 8 ++ .../ReferendumDetailsViewController.swift | 20 +++ .../ReferendumDetailsWireframe.swift | 19 +++ .../ReferendumVotingStatusDetailsView.swift | 41 ++++-- .../View/ReferendumVotingStatusView.swift | 1 + .../View/Rows/MultiValueView+Styles.swift | 37 ++++++ .../ReferendumDetails/View/VoteRowView.swift | 124 +++++++----------- .../ReferendumDisplayStringFactory.swift | 6 +- 10 files changed, 175 insertions(+), 93 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/MultiValueView+Styles.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 25fb09dd24..ed46d6fbf7 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1253,6 +1253,7 @@ 8485D924277E16C400767243 /* DAppBrowserScriptHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */; }; 8487010A2907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */; }; 8487010C2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8487010B2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift */; }; + 8487010E2907DF2F00F2C0C3 /* MultiValueView+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8487010D2907DF2F00F2C0C3 /* MultiValueView+Styles.swift */; }; 84873AFF26028E2B000A83EE /* StakingStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */; }; 84873B0426029B75000A83EE /* StakingEstimationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */; }; 84873B0926029CBD000A83EE /* StakingStateViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84873B0826029CBD000A83EE /* StakingStateViewModelFactory.swift */; }; @@ -4171,6 +4172,7 @@ 8485D923277E16C400767243 /* DAppBrowserScriptHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserScriptHandler.swift; sourceTree = ""; }; 848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumTimelineViewModelFactory.swift; sourceTree = ""; }; 8487010B2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumMetadataViewModelFactory.swift; sourceTree = ""; }; + 8487010D2907DF2F00F2C0C3 /* MultiValueView+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MultiValueView+Styles.swift"; sourceTree = ""; }; 84873AFE26028E2B000A83EE /* StakingStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingStateMachine.swift; sourceTree = ""; }; 84873B0326029B75000A83EE /* StakingEstimationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingEstimationViewModel.swift; sourceTree = ""; }; 84873B0826029CBD000A83EE /* StakingStateViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingStateViewModelFactory.swift; sourceTree = ""; }; @@ -12366,6 +12368,7 @@ 88F34FDE28FFEAE500712BDE /* TimelineRow.swift */, 88F34FE028FFEAFD00712BDE /* VotingDetailsRow.swift */, 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */, + 8487010D2907DF2F00F2C0C3 /* MultiValueView+Styles.swift */, ); path = Rows; sourceTree = ""; @@ -16190,6 +16193,7 @@ 8427495728FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift in Sources */, 84C5ADDF28133F3E006D7388 /* UnknownAddressView.swift in Sources */, 84F6B6502619E1ED0038F10D /* Int+Operations.swift in Sources */, + 8487010E2907DF2F00F2C0C3 /* MultiValueView+Styles.swift in Sources */, 85547F698B551ACD387D84E2 /* SelectValidatorsStartViewController.swift in Sources */, 41B29C1C9239BB2DCB7903A7 /* SelectValidatorsStartViewFactory.swift in Sources */, 25381484F16FB930B8A90CE3 /* SelectValidatorsConfirmProtocols.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index cc9f483ad4..e4b3614e41 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -265,6 +265,14 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { wireframe.presentAccountOptions(from: view, address: proposerAddress, chain: chain, locale: selectedLocale) } + func showAyeVoters() { + wireframe.showVoters(from: view, referendum: referendum, type: .ayes) + } + + func showNayVoters() { + wireframe.showVoters(from: view, referendum: referendum, type: .nays) + } + func readFullDescription() {} } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index a393eafded..64c7476fcc 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -12,6 +12,8 @@ protocol ReferendumDetailsPresenterProtocol: AnyObject { func setup() func showProposerDetails() func readFullDescription() + func showAyeVoters() + func showNayVoters() func vote() } @@ -47,4 +49,10 @@ protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, ) func showVote(from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal) + + func showVoters( + from view: ReferendumDetailsViewProtocol?, + referendum: ReferendumLocal, + type: ReferendumVotersType + ) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 0e4ecaefd6..9d90c1f616 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -53,6 +53,18 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { action: #selector(actionFullDescription), for: .touchUpInside ) + + rootView.votingDetailsRow.ayeVotesView.addTarget( + self, + action: #selector(actionAyeVotes), + for: .touchUpInside + ) + + rootView.votingDetailsRow.nayVotesView.addTarget( + self, + action: #selector(actionNayVotes), + for: .touchUpInside + ) } @objc private func actionVote() { @@ -66,6 +78,14 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { @objc private func actionFullDescription() { presenter.readFullDescription() } + + @objc private func actionAyeVotes() { + presenter.showAyeVoters() + } + + @objc private func actionNayVotes() { + presenter.showNayVoters() + } } extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index 2d07fbaab1..7888f06489 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -41,4 +41,23 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { view?.controller.present(navigationController, animated: true) } + + func showVoters( + from view: ReferendumDetailsViewProtocol?, + referendum: ReferendumLocal, + type: ReferendumVotersType + ) { + guard + let votersView = ReferendumVotersViewFactory.createView( + state: state, + referendum: referendum, + type: type + ) else { + return + } + + let navigationController = FearlessNavigationController(rootViewController: votersView.controller) + + view?.controller.present(navigationController, animated: true) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift index 9a06f707d7..8bb16d6b3b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -7,14 +7,14 @@ final class ReferendumVotingStatusDetailsView: RoundedView { let ayeVotesView: VoteRowView = .create { $0.apply(style: .init( color: R.color.colorRedFF3A69()!, - accessoryImage: R.image.iconInfo()! + accessoryImage: (R.image.iconInfoFilled()?.tinted(with: R.color.colorWhite48()!))! )) } let nayVotesView: VoteRowView = .create { $0.apply(style: .init( color: R.color.colorGreen15CF37()!, - accessoryImage: R.image.iconInfo()! + accessoryImage: (R.image.iconInfoFilled()?.tinted(with: R.color.colorWhite48()!))! )) } @@ -39,29 +39,48 @@ final class ReferendumVotingStatusDetailsView: RoundedView { } private func setupLayout() { + let votesContainerView = UIView.vStack( + [ + ayeVotesView, + nayVotesView + ] + ) + let content = UIView.vStack( - spacing: 16, [ statusView, votingProgressView, - UIView.vStack( - distribution: .fillEqually, - [ - ayeVotesView, - nayVotesView - ] - ), + votesContainerView, voteButton ] ) + + content.setCustomSpacing(16.0, after: votingProgressView) + content.setCustomSpacing(16.0, after: votesContainerView) + + content.alignment = .center + addSubview(content) content.snp.makeConstraints { - $0.edges.equalToSuperview().inset(16) + $0.top.bottom.equalToSuperview().inset(16) + $0.leading.trailing.equalToSuperview() } voteButton.snp.makeConstraints { make in make.height.equalTo(44.0) } + + votesContainerView.snp.makeConstraints { make in + make.width.equalTo(self) + } + + content.arrangedSubviews + .filter { $0 !== votesContainerView } + .forEach { + $0.snp.makeConstraints { make in + make.width.equalTo(self).offset(-32) + } + } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift index 926f2ccdb5..c1323c07d0 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift @@ -8,6 +8,7 @@ final class ReferendumVotingStatusView: UIView { $0.mode = .detailsIcon $0.detailsLabel.numberOfLines = 1 $0.spacing = 5 + $0.iconWidth = 14.0 $0.apply(style: .timeView) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/MultiValueView+Styles.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/MultiValueView+Styles.swift new file mode 100644 index 0000000000..f87a0b93a3 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/MultiValueView+Styles.swift @@ -0,0 +1,37 @@ +import UIKit + +extension MultiValueView { + struct Style { + let topLabel: UILabel.Style + let bottomLabel: UILabel.Style + } + + func apply(style: Style) { + valueTop.apply(style: style.topLabel) + valueBottom.apply(style: style.bottomLabel) + } +} + +extension MultiValueView.Style { + static let rowContrasted = MultiValueView.Style( + topLabel: .init( + textColor: R.color.colorWhite(), + font: .regularFootnote + ), + bottomLabel: .init( + textColor: R.color.colorWhite64(), + font: .caption1 + ) + ) + + static let accentAmount = MultiValueView.Style( + topLabel: .init( + textColor: R.color.colorWhite(), + font: .boldTitle1 + ), + bottomLabel: .init( + textColor: R.color.colorWhite64(), + font: .regularBody + ) + ) +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift index e0181b865e..e253980391 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/VoteRowView.swift @@ -1,28 +1,33 @@ import UIKit -import SwiftUI +import SoraUI -final class VoteRowView: UIView { - lazy var centerView = GenericTitleValueView( - titleView: titleLabel, - valueView: valueView - ) - - private let titleLabel = UILabel(style: .rowTitle, textAlignment: .left) - - private let valueView: MultiValueView = .create { - $0.apply(style: .rowContrasted) +final class VoteRowIndicatorView: RoundedView { + var preferredSize = CGSize(width: 4.0, height: 16.0) { + didSet { + invalidateIntrinsicContentSize() + } } - private var leadingRectangleView: UIView = .create { - $0.layer.cornerRadius = 4 + override var intrinsicContentSize: CGSize { + preferredSize } +} + +final class VoteRowView: RowView< + GenericTitleValueView, IconDetailsView> +> { + var titleLabel: UILabel { rowContentView.titleView.sView } + + var detailsLabel: UILabel { rowContentView.valueView.detailsLabel } - private var trailingImageView = UIImageView() + var indicatorView: RoundedView { rowContentView.titleView.fView } + + var trailingImageView: UIImageView { rowContentView.valueView.imageView } override init(frame: CGRect) { super.init(frame: frame) - setupLayout() + configureStyle() } @available(*, unavailable) @@ -30,33 +35,21 @@ final class VoteRowView: UIView { fatalError("init(coder:) has not been implemented") } - private func setupLayout() { - let contentView = UIView.hStack( - alignment: .center, - distribution: .fill, - spacing: 8, - [ - leadingRectangleView, - centerView, - trailingImageView - ] - ) - contentView.setCustomSpacing(16, after: leadingRectangleView) - addSubview(contentView) - trailingImageView.snp.makeConstraints { - $0.height.width.equalTo(16) - } - leadingRectangleView.snp.makeConstraints { - $0.height.equalTo(16) - $0.width.equalTo(4) - } - contentView.snp.makeConstraints { - $0.edges.equalToSuperview() - } - } + private func configureStyle() { + preferredHeight = 44.0 + roundedBackgroundView.highlightedFillColor = R.color.colorHighlightedAccent()! + borderView.borderType = .none - override var intrinsicContentSize: CGSize { - .init(width: UIView.noIntrinsicMetric, height: 44) + rowContentView.titleView.setHorizontalAndSpacing(16.0) + rowContentView.valueView.spacing = 8.0 + rowContentView.valueView.mode = .detailsIcon + + indicatorView.cornerRadius = 2.0 + + rowContentView.valueView.iconWidth = 16.0 + + titleLabel.apply(style: UILabel.Style.rowTitle) + detailsLabel.apply(style: UILabel.Style.rowTitle) } } @@ -67,59 +60,34 @@ extension VoteRowView { } func apply(style: Style) { - leadingRectangleView.backgroundColor = style.color + indicatorView.fillColor = style.color trailingImageView.image = style.accessoryImage + + setNeedsLayout() } } -extension VoteRowView: BindableView { +extension VoteRowView { struct Model { let title: String let votes: String - let tokens: String? } func bind(viewModel: Model) { titleLabel.text = viewModel.title - valueView.bind(topValue: viewModel.votes, bottomValue: viewModel.tokens) + detailsLabel.text = viewModel.votes } -} -extension MultiValueView { - struct Style { - let topLabel: UILabel.Style - let bottomLabel: UILabel.Style - } - - func apply(style: Style) { - valueTop.apply(style: style.topLabel) - valueBottom.apply(style: style.bottomLabel) + func bindOrHide(viewModel: Model?) { + if let viewModel = viewModel { + isHidden = false + bind(viewModel: viewModel) + } else { + isHidden = true + } } } -extension MultiValueView.Style { - static let rowContrasted = MultiValueView.Style( - topLabel: .init( - textColor: R.color.colorWhite(), - font: .regularFootnote - ), - bottomLabel: .init( - textColor: R.color.colorWhite64(), - font: .caption1 - ) - ) - static let accentAmount = MultiValueView.Style( - topLabel: .init( - textColor: R.color.colorWhite(), - font: .boldTitle1 - ), - bottomLabel: .init( - textColor: R.color.colorWhite64(), - font: .regularBody - ) - ) -} - extension UILabel.Style { static let rowTitle = UILabel.Style(textColor: R.color.colorWhite(), font: .regularFootnote) } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift index aa78f7eab6..c2b383604f 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift @@ -34,16 +34,14 @@ extension ReferendumDisplayStringFactoryProtocol { let aye: VoteRowView.Model? = ayesString.map { .init( title: R.string.localizable.governanceAye(preferredLanguages: locale.rLanguages), - votes: $0, - tokens: nil + votes: $0 ) } let nay: VoteRowView.Model? = naysString.map { .init( title: R.string.localizable.governanceNay(preferredLanguages: locale.rLanguages), - votes: $0, - tokens: nil + votes: $0 ) } From a1e68952798cf3c842798d109181b0d626ec023d Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 25 Oct 2022 23:55:16 +0500 Subject: [PATCH 097/229] fix voters --- .../ReferendumVotersPresenter.swift | 13 ++++++++++++- .../ReferendumVotersProtocols.swift | 4 ++-- .../ReferendumVotersViewController.swift | 10 +++++++--- novawallet/en.lproj/Localizable.strings | 2 +- novawallet/ru.lproj/Localizable.strings | 2 +- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift index 9a0ce6f172..cb125f793d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift @@ -102,7 +102,18 @@ extension ReferendumVotersPresenter: ReferendumVotersPresenterProtocol { interactor.setup() } - func selectVoter(at _: Int) {} + func selectVoter(for viewModel: ReferendumVotersViewModel) { + guard let view = view else { + return + } + + wireframe.presentAccountOptions( + from: view, + address: viewModel.displayAddress.address, + chain: chain, + locale: selectedLocale + ) + } } extension ReferendumVotersPresenter: ReferendumVotersInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift index 01a5ee09c3..8258f7b27d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersProtocols.swift @@ -5,7 +5,7 @@ protocol ReferendumVotersViewProtocol: ControllerBackedProtocol { protocol ReferendumVotersPresenterProtocol: AnyObject { func setup() - func selectVoter(at index: Int) + func selectVoter(for viewModel: ReferendumVotersViewModel) } protocol ReferendumVotersInteractorInputProtocol: AnyObject { @@ -18,4 +18,4 @@ protocol ReferendumVotersInteractorOutputProtocol: AnyObject { func didReceiveError(_ error: ReferendumVotersInteractorError) } -protocol ReferendumVotersWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable {} +protocol ReferendumVotersWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, AddressOptionsPresentable {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift index 66d5eb7e12..0339c1d2de 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewController.swift @@ -110,7 +110,11 @@ extension ReferendumVotersViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) - presenter.selectVoter(at: indexPath.row) + guard let viewModels = state?.value else { + return + } + + presenter.selectVoter(for: viewModels[indexPath.row]) } } @@ -123,9 +127,9 @@ extension ReferendumVotersViewController: EmptyStateViewOwnerProtocol { extension ReferendumVotersViewController: EmptyStateDataSource { var viewForEmptyState: UIView? { let emptyView = EmptyStateView() - emptyView.image = R.image.iconSearchHappy()?.tinted(with: R.color.colorWhite()!) + emptyView.image = R.image.iconEmptyHistory() emptyView.title = R.string.localizable.govVotersEmpty(preferredLanguages: selectedLocale.rLanguages) - emptyView.titleColor = R.color.colorWhite()! + emptyView.titleColor = R.color.colorTransparentText()! emptyView.titleFont = .regularFootnote return emptyView } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 4e8f379104..eb03ba980c 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1025,7 +1025,7 @@ "gov.voters.nay" = "Nay voters"; "gov.common.votes.format" = "%@ votes"; "gov.common.amount.conviction.format" = "%@ × %@x"; -"gov.voters.empty" = "When somebody votes for\nthe referendum they will appear here"; +"gov.voters.empty" = "List of voters will appear here"; "gov.vote.conviction.title" = "Multiply votes by increasing locking period"; "common.gov.lock" = "Governance lock"; "common.locking.period" = "Locking period"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 90a3937ee9..a014490fbd 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1026,7 +1026,7 @@ "gov.voters.nay" = "Против голосовали"; "gov.common.votes.format" = "%@ голосов"; "gov.common.amount.conviction.format" = "%@ × %@x"; -"gov.voters.empty" = "Когда кто-нибудь проголосует\nза референдум они будут отображаться здесь"; +"gov.voters.empty" = "Список проголосовавших появится здесь"; "gov.vote.conviction.title" = "Умножить голос, увеличивая период блокировки"; "common.gov.lock" = "Блокировка в голосовании"; "common.locking.period" = "Период блокировки"; From 678288a4eff9d52678cd2aee6eac9aa532ac9846 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 26 Oct 2022 00:15:11 +0500 Subject: [PATCH 098/229] fix dapps --- .../ReferendumDetailsPresenter.swift | 4 ++++ .../ReferendumDetailsProtocols.swift | 1 + .../ReferendumDetailsViewController.swift | 17 ++++++++++++++++- .../ReferendumDetailsViewLayout.swift | 16 ++++++++++++---- .../ReferendumVotingStatusDetailsView.swift | 4 ++-- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index e4b3614e41..3e7a066385 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -273,6 +273,10 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { wireframe.showVoters(from: view, referendum: referendum, type: .nays) } + func opeDApp(at index: Int) { + + } + func readFullDescription() {} } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 64c7476fcc..995c9ae648 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -14,6 +14,7 @@ protocol ReferendumDetailsPresenterProtocol: AnyObject { func readFullDescription() func showAyeVoters() func showNayVoters() + func opeDApp(at index: Int) func vote() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 9d90c1f616..362d06d1f9 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -8,6 +8,8 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { let presenter: ReferendumDetailsPresenterProtocol let localizationManager: LocalizationManagerProtocol + private var dAppCells: [ReferendumDAppCellView]? + init( presenter: ReferendumDetailsPresenterProtocol, localizationManager: LocalizationManagerProtocol @@ -86,6 +88,16 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { @objc private func actionNayVotes() { presenter.showNayVoters() } + + @objc private func actionDApp(_ sender: UIControl) { + guard + let cell = sender as? ReferendumDAppCellView, + let index = dAppCells?.firstIndex(of: cell) else { + return + } + + presenter.opeDApp(at: index) + } } extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { @@ -94,7 +106,10 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { } func didReceive(dAppModels: [ReferendumDAppView.Model]?) { - rootView.setDApps(models: dAppModels, locale: localizationManager.selectedLocale) + let cells = rootView.setDApps(models: dAppModels, locale: localizationManager.selectedLocale) + dAppCells = cells + + cells.forEach { $0.addTarget(self, action: #selector(actionDApp(_:)), for: .touchUpInside)} } func didReceive(timelineModel: [ReferendumTimelineView.Model]?) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 54ac95bced..afb9b4a04c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -70,7 +70,7 @@ final class ReferendumDetailsViewLayout: UIView { } } - func setDApps(models: [ReferendumDAppView.Model]?, locale: Locale) { + func setDApps(models: [ReferendumDAppView.Model]?, locale: Locale) -> [ReferendumDAppCellView] { dAppsTableView.clear() if let models = models { @@ -81,15 +81,23 @@ final class ReferendumDetailsViewLayout: UIView { ) let headerView = createHeader(with: title) - dAppsTableView.stackView.addArrangedSubview(headerView) + dAppsTableView.addArrangedSubview(headerView) - for model in models { + let cells: [ReferendumDAppCellView] = models.map { model in let dAppView = ReferendumDAppCellView(frame: .zero) dAppView.rowContentView.bind(viewModel: model) - dAppsTableView.stackView.addArrangedSubview(dAppView) + return dAppView } + + cells.forEach { + dAppsTableView.addArrangedSubview($0) + } + + return cells } else { dAppsTableView.isHidden = true + + return [] } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift index 8bb16d6b3b..25d3a214b3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusDetailsView.swift @@ -6,14 +6,14 @@ final class ReferendumVotingStatusDetailsView: RoundedView { let votingProgressView = VotingProgressView() let ayeVotesView: VoteRowView = .create { $0.apply(style: .init( - color: R.color.colorRedFF3A69()!, + color: R.color.colorGreen15CF37()!, accessoryImage: (R.image.iconInfoFilled()?.tinted(with: R.color.colorWhite48()!))! )) } let nayVotesView: VoteRowView = .create { $0.apply(style: .init( - color: R.color.colorGreen15CF37()!, + color: R.color.colorRedFF3A69()!, accessoryImage: (R.image.iconInfoFilled()?.tinted(with: R.color.colorWhite48()!))! )) } From 109739626ca412edef9e27d955341ae137dbbc5a Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 26 Oct 2022 10:13:28 +0500 Subject: [PATCH 099/229] fix requested amount --- .../Substrate/Types/Treasury/Treasury+Calls.swift | 2 +- .../Substrate/Types/Treasury/TreasuryProposal.swift | 2 +- .../Vote/Governance/Model/ReferendumActionLocal.swift | 2 +- .../Operation/Gov2ActionOperationFactory.swift | 4 ++-- .../ReferendumDetailsInteractor.swift | 6 +++++- .../ReferendumDetails/ReferendumDetailsPresenter.swift | 4 +--- .../ReferendumDetailsViewController.swift | 2 +- .../ReferendumDetailsViewLayout.swift | 10 +++++++--- .../ReferendumDetails/View/ReferendumDAppView.swift | 4 +++- .../View/Rows/ReferendumDAppCellView.swift | 10 +--------- .../View/Rows/RequestedAmountRow.swift | 1 + 11 files changed, 24 insertions(+), 23 deletions(-) diff --git a/novawallet/Common/Substrate/Types/Treasury/Treasury+Calls.swift b/novawallet/Common/Substrate/Types/Treasury/Treasury+Calls.swift index 618cc1c761..878d8bd345 100644 --- a/novawallet/Common/Substrate/Types/Treasury/Treasury+Calls.swift +++ b/novawallet/Common/Substrate/Types/Treasury/Treasury+Calls.swift @@ -21,6 +21,6 @@ extension Treasury { struct SpendCall: Decodable { @StringCodable var amount: BigUInt - let beneficiary: AccountId + let beneficiary: MultiAddress } } diff --git a/novawallet/Common/Substrate/Types/Treasury/TreasuryProposal.swift b/novawallet/Common/Substrate/Types/Treasury/TreasuryProposal.swift index 4ab48ade27..bb22e6baa4 100644 --- a/novawallet/Common/Substrate/Types/Treasury/TreasuryProposal.swift +++ b/novawallet/Common/Substrate/Types/Treasury/TreasuryProposal.swift @@ -6,6 +6,6 @@ extension Treasury { struct Proposal: Decodable { let proposer: AccountId @StringCodable var value: BigUInt - let beneficiary: AccountId + @BytesCodable var beneficiary: AccountId } } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift index dda83a3ebc..e6bf4cccee 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift @@ -5,7 +5,7 @@ import SubstrateSdk struct ReferendumActionLocal { struct AmountSpendDetails { let amount: BigUInt - let beneficiaryAccountId: AccountId + let beneficiary: MultiAddress } let amountSpendDetails: AmountSpendDetails? diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift index 11c8d879cd..8424d238ff 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift @@ -135,7 +135,7 @@ final class Gov2ActionOperationFactory { let details = ReferendumActionLocal.AmountSpendDetails( amount: spendCall.amount, - beneficiaryAccountId: spendCall.beneficiary + beneficiary: spendCall.beneficiary ) return [CompoundOperationWrapper.createWithResult(details)] @@ -163,7 +163,7 @@ final class Gov2ActionOperationFactory { return ReferendumActionLocal.AmountSpendDetails( amount: proposal.value, - beneficiaryAccountId: proposal.beneficiary + beneficiary: .accoundId(proposal.beneficiary) ) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index a9472aa448..c8a8c1ed07 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -155,7 +155,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { accountIds.append(proposer) } - if let beneficiary = actionDetails?.amountSpendDetails?.beneficiaryAccountId { + if let beneficiary = actionDetails?.amountSpendDetails?.beneficiary.accountId { accountIds.append(beneficiary) } @@ -255,6 +255,10 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { } } } + + actionDetailsCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } private func makeSubscriptions() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 3e7a066385..3dbe00c893 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -273,9 +273,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { wireframe.showVoters(from: view, referendum: referendum, type: .nays) } - func opeDApp(at index: Int) { - - } + func opeDApp(at _: Int) {} func readFullDescription() {} } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 362d06d1f9..b3930b3dd8 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -109,7 +109,7 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { let cells = rootView.setDApps(models: dAppModels, locale: localizationManager.selectedLocale) dAppCells = cells - cells.forEach { $0.addTarget(self, action: #selector(actionDApp(_:)), for: .touchUpInside)} + cells.forEach { $0.addTarget(self, action: #selector(actionDApp(_:)), for: .touchUpInside) } } func didReceive(timelineModel: [ReferendumTimelineView.Model]?) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index afb9b4a04c..0d2b82ebad 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -11,7 +11,11 @@ final class ReferendumDetailsViewLayout: UIView { let titleView = ReferendumDetailsTitleView() let votingDetailsRow = ReferendumVotingStatusDetailsView() - let dAppsTableView = StackTableView() + let dAppsTableView: StackTableView = .create { + $0.cellHeight = 64.0 + $0.contentInsets = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 8.0, right: 16.0) + } + var timelineTableView = StackTableView() var yourVoteRow: YourVoteRow? @@ -81,10 +85,11 @@ final class ReferendumDetailsViewLayout: UIView { ) let headerView = createHeader(with: title) + dAppsTableView.setCustomHeight(32, at: 0) dAppsTableView.addArrangedSubview(headerView) let cells: [ReferendumDAppCellView] = models.map { model in - let dAppView = ReferendumDAppCellView(frame: .zero) + let dAppView = ReferendumDAppCellView() dAppView.rowContentView.bind(viewModel: model) return dAppView } @@ -137,7 +142,6 @@ final class ReferendumDetailsViewLayout: UIView { let headerView = StackTableHeaderCell() headerView.titleLabel.apply(style: .footnoteWhite64) headerView.titleLabel.text = text - headerView.contentInsets = .init(top: 16, left: 16, bottom: 8, right: 16) return headerView } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift index d53028ebe0..d8a1af27ac 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDAppView.swift @@ -37,9 +37,11 @@ final class ReferendumDAppView: UIView { arrowView ] ) + arrowView.snp.makeConstraints { - $0.size.equalTo(Constants.arrowSize) + $0.width.height.equalTo(Constants.arrowSize) } + iconImageView.snp.makeConstraints { $0.width.height.equalTo(Constants.iconWidth) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift index 3f055786f4..d6405973e5 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/ReferendumDAppCellView.swift @@ -1,11 +1,3 @@ import UIKit -final class ReferendumDAppCellView: RowView, StackTableViewCellProtocol { - override init(frame: CGRect) { - super.init(frame: frame) - - backgroundColor = .clear - preferredHeight = 64 - contentInsets = .init(top: 8, left: 16, bottom: 8, right: 16) - } -} +final class ReferendumDAppCellView: RowView, StackTableViewCellProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift index 290a75c0fd..1e8124e794 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/RequestedAmountRow.swift @@ -19,6 +19,7 @@ final class RequestedAmountRow: RowView> { contentInsets = .init(top: 16, left: 16, bottom: 16, right: 16) backgroundColor = .clear isUserInteractionEnabled = false + borderView.borderType = .none } func bind(viewModel: Model) { From f740c0e2bc338976350b4edb42c571a6c49b81ea Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 26 Oct 2022 11:57:15 +0500 Subject: [PATCH 100/229] fix timeline --- .../ReferendumDetailsViewLayout.swift | 24 ++--- .../View/Rows/TimelineRow.swift | 43 ++++++++- .../View/Timeline/DotsView.swift | 80 ++++++++++------- .../Timeline/ReferendumTimelineView.swift | 89 +++++++++++++------ .../ReferendumTimelineViewModelFactory.swift | 18 ++-- 5 files changed, 172 insertions(+), 82 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 0d2b82ebad..922f32bbc6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -16,7 +16,7 @@ final class ReferendumDetailsViewLayout: UIView { $0.contentInsets = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 8.0, right: 16.0) } - var timelineTableView = StackTableView() + var timelineView = TimelineRow() var yourVoteRow: YourVoteRow? var requestedAmountRow: RequestedAmountRow? @@ -48,30 +48,20 @@ final class ReferendumDetailsViewLayout: UIView { containerView.stackView.addArrangedSubview(votingDetailsRow) containerView.stackView.addArrangedSubview(dAppsTableView) - containerView.stackView.addArrangedSubview(timelineTableView) + containerView.stackView.addArrangedSubview(timelineView) containerView.stackView.addArrangedSubview(fullDetailsView) - timelineTableView.apply(style: .cellWithoutHighlighting) dAppsTableView.apply(style: .cellWithoutHighlighting) } func setTimeline(model: [ReferendumTimelineView.Model]?, locale: Locale) { - timelineTableView.clear() + let title = R.string.localizable.govReferendumDetailsTimelineTitle( + preferredLanguages: locale.rLanguages + ) - if let model = model { - timelineTableView.isHidden = false + timelineView.titleLabel.text = title - let title = R.string.localizable.govReferendumDetailsTimelineTitle( - preferredLanguages: locale.rLanguages - ) - let headerView = createHeader(with: title) - let timelineRow = TimelineRow(frame: .zero) - timelineRow.bind(viewModel: model) - timelineTableView.stackView.addArrangedSubview(headerView) - timelineTableView.stackView.addArrangedSubview(timelineRow) - } else { - timelineTableView.isHidden = true - } + timelineView.bindOrHide(viewModel: model) } func setDApps(models: [ReferendumDAppView.Model]?, locale: Locale) -> [ReferendumDAppCellView] { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift index 21a7f66923..25edd16e93 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift @@ -1,11 +1,48 @@ import UIKit +import SoraUI + +final class TimelineRow: RoundedView, BindableView { + typealias TModel = [ReferendumTimelineView.Model] + + let titleLabel: UILabel = .create { + $0.textColor = R.color.colorTransparentText() + $0.font = .regularFootnote + } + + let contentView = ReferendumTimelineView() -final class TimelineRow: RowView, StackTableViewCellProtocol { override init(frame: CGRect) { super.init(frame: frame) - isUserInteractionEnabled = false - contentInsets = .init(top: 8, left: 16, bottom: 0, right: 16) backgroundColor = .clear + + applyCellBackgroundStyle() + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func bind(viewModel: [ReferendumTimelineView.Model]) { + contentView.bind(viewModel: viewModel) + } + + private func setupLayout() { + let content = UIView.vStack( + spacing: 16, + [ + titleLabel, + contentView + ] + ) + + addSubview(content) + content.snp.makeConstraints { make in + make.top.leading.trailing.equalToSuperview().inset(16) + make.bottom.equalToSuperview() + } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift index 0a6de9d5d9..8deec936f6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/DotsView.swift @@ -2,13 +2,20 @@ import UIKit final class DotsView: UIView { struct Model { - let view: BaselinedView let isFinite: Bool } - var points: [Model] = [] + var points: [Model] = [] { + didSet { + invalidateIntrinsicContentSize() + setNeedsDisplay() + } + } + private var style: Style = .defaultStyle + var contentInsets = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1) + override init(frame: CGRect) { super.init(frame: frame) @@ -25,43 +32,50 @@ final class DotsView: UIView { drawDots() } + override var intrinsicContentSize: CGSize { + let height = CGFloat(points.count) * (2 * style.dotRadius + style.pointSpacing) + style.lastExtraSpace + + return CGSize( + width: 2 * style.dotRadius + contentInsets.left + contentInsets.right, + height: height + contentInsets.top + contentInsets.bottom + ) + } + private func drawDots() { - guard let context = UIGraphicsGetCurrentContext(), - let superview = superview else { + guard let context = UIGraphicsGetCurrentContext() else { return } + setup(context: context) - let dotX = frame.midX + let dotX = bounds.midX for index in 0 ..< points.count { - let dotY = points[index].view.firstBaseline.frame(in: superview).midY + let dotY = bounds.minY + contentInsets.top + CGFloat(index) * (2 * style.dotRadius + style.pointSpacing) + + style.dotRadius let firstDot = createCircle(with: .init(x: dotX, y: dotY)) - firstDot.move(to: .init(x: dotX, y: dotY + style.dotRadius + style.space)) - let nextDotY: CGFloat if index == points.count - 1 { firstDot.stroke() firstDot.fill() - guard !points[index].isFinite else { - continue + if !points[index].isFinite { + let dottedLinePath = UIBezierPath() + let lineStart = dotY + style.dotRadius + style.lineSpacing + let lineEnd = dotY + style.dotRadius + style.pointSpacing + style.lastExtraSpace + dottedLinePath.move(to: .init(x: dotX, y: lineStart)) + dottedLinePath.setLineDash(style.pattern, count: style.pattern.count, phase: 0) + dottedLinePath.addLine(to: .init(x: dotX, y: lineEnd)) + + context.setStrokeColor(style.dashedColor.cgColor) + dottedLinePath.stroke() } - let dottedLinePath = UIBezierPath() - nextDotY = frame.maxY - dottedLinePath.move(to: .init(x: dotX, y: dotY + style.dotRadius + style.space)) - dottedLinePath.setLineDash(style.pattern, count: style.pattern.count, phase: 0) - dottedLinePath.addLine(to: .init(x: dotX, y: nextDotY)) - dottedLinePath.stroke() - dottedLinePath.fill() } else { - nextDotY = points[index + 1].view.firstBaseline.frame(in: superview).midY - firstDot.addLine(to: .init(x: dotX, y: nextDotY - style.dotRadius - style.space)) + let lineStart = dotY + style.dotRadius + style.lineSpacing + let lineEnd = dotY + style.dotRadius + style.pointSpacing - style.lineSpacing + firstDot.move(to: .init(x: dotX, y: lineStart)) + firstDot.addLine(to: .init(x: dotX, y: lineEnd)) firstDot.stroke() firstDot.fill() - - let secondDot = createCircle(with: .init(x: dotX, y: nextDotY)) - secondDot.stroke() - secondDot.fill() } } } @@ -77,8 +91,8 @@ final class DotsView: UIView { } private func setup(context: CGContext) { - context.setStrokeColor(style.color.cgColor) - context.setFillColor(style.color.cgColor) + context.setStrokeColor(style.connectingColor.cgColor) + context.setFillColor(style.connectingColor.cgColor) context.setLineWidth(style.lineWidth) } } @@ -86,10 +100,13 @@ final class DotsView: UIView { extension DotsView { struct Style { let lineWidth: CGFloat - let color: UIColor + let connectingColor: UIColor + let dashedColor: UIColor let dotRadius: CGFloat - let space: CGFloat + let pointSpacing: CGFloat + let lineSpacing: CGFloat let pattern: [CGFloat] + let lastExtraSpace: CGFloat } func apply(style: Style) { @@ -102,9 +119,12 @@ extension DotsView { extension DotsView.Style { static let defaultStyle = DotsView.Style( lineWidth: 1, - color: R.color.colorNovaBlue()!, + connectingColor: R.color.colorNovaBlue()!, + dashedColor: R.color.colorWhite24()!, dotRadius: 6, - space: 6, - pattern: [2, 3] + pointSpacing: 36, + lineSpacing: 6, + pattern: [2, 3], + lastExtraSpace: 4 ) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift index 7641997906..bf47a6f6fa 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift @@ -2,11 +2,16 @@ import UIKit import SoraUI final class ReferendumTimelineView: UIView { - let dotsView = DotsView() - let statusesContentView: UIStackView = .create { - $0.axis = .vertical + private enum Constants { + static let horizontalSpacing: CGFloat = 15 + static let verticalSpacing: CGFloat = 48 + static let alignmentOffset: CGFloat = -1 + static let titleSubtitleSpacing: CGFloat = 2 } + let dotsView = DotsView() + private var statusViews: [UIView] = [] + override init(frame: CGRect) { super.init(frame: frame) @@ -20,54 +25,73 @@ final class ReferendumTimelineView: UIView { private func setupLayout() { addSubview(dotsView) - addSubview(statusesContentView) dotsView.snp.makeConstraints { $0.top.bottom.leading.equalToSuperview() - $0.width.equalTo(14) - } - - statusesContentView.spacing = 12 - statusesContentView.snp.makeConstraints { - $0.top.trailing.equalToSuperview() - $0.bottom.equalToSuperview().inset(20) - $0.leading.equalTo(dotsView.snp.trailing).inset(-16) } } private func updateStatuses(model: [Model]) { let statusViews = statusViews(from: model) - statusesContentView.arrangedSubviews.forEach { - statusesContentView.removeArrangedSubview($0) + + self.statusViews.forEach { + $0.removeFromSuperview() } - statusViews.forEach { - statusesContentView.addArrangedSubview($0.view) + + self.statusViews = statusViews + + statusViews.enumerated().forEach { index, view in + addSubview(view) + + let topInset = CGFloat(index) * Constants.verticalSpacing + Constants.alignmentOffset + + view.snp.makeConstraints { make in + make.leading.equalTo(dotsView.snp.trailing).offset(Constants.horizontalSpacing) + make.top.equalToSuperview().inset(topInset) + } } - dotsView.points = statusViews.map { - DotsView.Model(view: $0.view, isFinite: $0.status.isLast) + + dotsView.points = model.map { + DotsView.Model(isFinite: $0.isLast) } } - private func statusViews(from model: [Model]) -> [(view: BaselinedView, status: Model)] { + private func statusViews(from model: [Model]) -> [UIView] { model.map { status in switch status.subtitle { case let .date(date): let view = MultiValueView() + view.spacing = Constants.titleSubtitleSpacing view.valueTop.text = status.title view.valueTop.textAlignment = .left + view.valueTop.apply(style: UILabel.Style.timelineTitle) + view.valueBottom.apply(style: UILabel.Style.timelineNeutralSubtitle) view.valueBottom.textAlignment = .left view.valueBottom.text = date - return (view: view, status: status) + return view case let .interval(model): let view = GenericMultiValueView() + view.spacing = Constants.titleSubtitleSpacing view.valueTop.text = status.title view.valueTop.textAlignment = .left - view.valueBottom.bind(viewModel: model) - return (view: view, status: status) + view.valueTop.apply(style: UILabel.Style.timelineTitle) + view.valueBottom.detailsLabel.numberOfLines = 1 + + if model.isUrgent { + view.valueBottom.detailsLabel.apply(style: UILabel.Style.timelineUrgentSubtitle) + } else { + view.valueBottom.detailsLabel.apply(style: UILabel.Style.timelineNeutralSubtitle) + } + + view.valueBottom.spacing = 5 + view.valueBottom.iconWidth = 14 + view.valueBottom.bind(viewModel: model.titleIcon) + return view case .none: let label = UILabel() label.text = status.title - return (view: label, status: status) + label.apply(style: UILabel.Style.rowTitle) + return label } } } @@ -82,12 +106,25 @@ extension ReferendumTimelineView: BindableView { enum StatusSubtitle { case date(String) - case interval(TitleIconViewModel) + case interval(ReferendumInfoView.Model.Time) } func bind(viewModel: [Model]) { updateStatuses(model: viewModel) - dotsView.setNeedsDisplay() - dotsView.setNeedsLayout() + setNeedsLayout() + } +} + +private extension UILabel.Style { + static var timelineTitle: UILabel.Style { + .init(textColor: R.color.colorWhite()!, font: .regularFootnote) + } + + static var timelineNeutralSubtitle: UILabel.Style { + .init(textColor: R.color.colorTransparentText()!, font: .caption1) + } + + static var timelineUrgentSubtitle: UILabel.Style { + .init(textColor: R.color.colorDarkYellow()!, font: .caption1) } } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift index cc62e4d6c2..789f09ad08 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift @@ -93,7 +93,7 @@ final class ReferendumTimelineViewModelFactory { preferredLanguages: locale.rLanguages ) - let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel.titleIcon) } + let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel) } return .init( title: title, @@ -128,7 +128,7 @@ final class ReferendumTimelineViewModelFactory { preferredLanguages: locale.rLanguages ) - let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel.titleIcon) } + let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel) } return .init( title: title, @@ -139,7 +139,9 @@ final class ReferendumTimelineViewModelFactory { } private func createApprovedTitle(for locale: Locale) -> String { - let votingTitle = R.string.localizable.governanceReferendumsStatusApproved(preferredLanguages: locale.rLanguages) + let votingTitle = R.string.localizable.governanceReferendumsStatusApproved( + preferredLanguages: locale.rLanguages + ) return R.string.localizable.govTimelineVotedFormat( votingTitle.lowercased().firstLetterCapitalized(), @@ -162,7 +164,7 @@ final class ReferendumTimelineViewModelFactory { let title = createApprovedTitle(for: locale) - let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel.titleIcon) } + let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel) } return .init( title: title, @@ -260,7 +262,9 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory createdAt = nil let cancelled = createVotedTerminal( - status: R.string.localizable.governanceReferendumsStatusCancelled(preferredLanguages: locale.rLanguages), + status: R.string.localizable.governanceReferendumsStatusCancelled( + preferredLanguages: locale.rLanguages + ), atBlock: atBlock, currentBlock: currentBlock, blockTime: blockDuration, @@ -302,7 +306,9 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory ) let executed = ReferendumTimelineView.Model( - title: R.string.localizable.governanceReferendumsStatusExecuted(preferredLanguages: locale.rLanguages), + title: R.string.localizable.governanceReferendumsStatusExecuted( + preferredLanguages: locale.rLanguages + ).firstLetterCapitalized(), subtitle: nil, isLast: true ) From 1c46310c90c2fab7484307b884b5a028397131f0 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 26 Oct 2022 12:16:23 +0500 Subject: [PATCH 101/229] handle full details --- .../ReferendumDetailsPresenter.swift | 10 ++++++++++ .../ReferendumDetailsProtocols.swift | 2 ++ .../ReferendumDetailsViewController.swift | 14 ++++++++++++++ .../ReferendumDetailsViewLayout.swift | 6 ++++++ .../View/Rows/FullDetailsRow.swift | 1 + novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 7 files changed, 35 insertions(+) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 3dbe00c893..107857b675 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -233,6 +233,11 @@ final class ReferendumDetailsPresenter { view?.didReceive(timelineModel: timeline) } + private func provideFullDetailsViewModel() { + let shouldHide = actionDetails == nil && referendumMetadata == nil + view?.didReceive(shouldHideFullDetails: shouldHide) + } + private func updateView() { provideReferendumInfoViewModel() provideTitleViewModel() @@ -241,6 +246,7 @@ final class ReferendumDetailsPresenter { provideVotingDetails() provideDAppViewModel() provideTimelineViewModel() + provideFullDetailsViewModel() } } @@ -276,6 +282,8 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { func opeDApp(at _: Int) {} func readFullDescription() {} + + func openFullDetails() {} } extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol { @@ -292,6 +300,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol provideTitleViewModel() provideRequestedAmount() + provideFullDetailsViewModel() } func didReceiveAccountVotes(_ votes: ReferendumAccountVoteLocal?) { @@ -304,6 +313,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol self.referendumMetadata = referendumMetadata provideTitleViewModel() + provideFullDetailsViewModel() } func didReceiveIdentities(_ identities: [AccountAddress: AccountIdentity]) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 995c9ae648..ea860a5a17 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -6,6 +6,7 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { func didReceive(yourVoteModel: YourVoteRow.Model?) func didReceive(requestedAmount: RequestedAmountRow.Model?) func didReceive(trackTagsModel: TrackTagsView.Model?) + func didReceive(shouldHideFullDetails: Bool) } protocol ReferendumDetailsPresenterProtocol: AnyObject { @@ -15,6 +16,7 @@ protocol ReferendumDetailsPresenterProtocol: AnyObject { func showAyeVoters() func showNayVoters() func opeDApp(at index: Int) + func openFullDetails() func vote() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index b3930b3dd8..400a21e124 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -67,6 +67,12 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { action: #selector(actionNayVotes), for: .touchUpInside ) + + rootView.fullDetailsView.addTarget( + self, + action: #selector(actionFullDetails), + for: .touchUpInside + ) } @objc private func actionVote() { @@ -98,6 +104,10 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { presenter.opeDApp(at: index) } + + @objc private func actionFullDetails() { + presenter.openFullDetails() + } } extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { @@ -136,4 +146,8 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { } navigationItem.setRightBarButton(barButtonItem, animated: true) } + + func didReceive(shouldHideFullDetails: Bool) { + rootView.setFullDetails(hidden: shouldHideFullDetails, locale: localizationManager.selectedLocale) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 922f32bbc6..c1ef48d90a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -128,6 +128,12 @@ final class ReferendumDetailsViewLayout: UIView { requestedAmountRow?.bind(viewModel: requestedAmountViewModel) } + func setFullDetails(hidden: Bool, locale: Locale) { + fullDetailsView.isHidden = hidden + + fullDetailsView.bind(title: R.string.localizable.commonFullDetails(preferredLanguages: locale.rLanguages)) + } + private func createHeader(with text: String) -> StackTableHeaderCell { let headerView = StackTableHeaderCell() headerView.titleLabel.apply(style: .footnoteWhite64) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift index 4b4e2a640d..ecdee91ca7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/FullDetailsRow.swift @@ -11,6 +11,7 @@ final class FullDetailsRow: RowView> roundedBackgroundView.apply(style: .roundedLightCell) preferredHeight = 52 contentInsets = .init(top: 14, left: 16, bottom: 14, right: 16) + borderView.borderType = .none } func bind(title: String) { diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index eb03ba980c..07c3416c0d 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1057,3 +1057,4 @@ "common.read.more" = "Read more"; "gov.referendum.title.fallback" = "Referendum %@"; "gov.referendum.description.fallback" = "Only the proposer can edit this description and the title. If you own proposer's account, visit Polkassembly and fill in information about your proposal"; +"common.full.details" = "Full details"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index a014490fbd..8f99ed2cd2 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1058,3 +1058,4 @@ "common.read.more" = "Читать дальше"; "gov.referendum.title.fallback" = "Референдум %@"; "gov.referendum.description.fallback" = "Только создатель референдума может редактировать заголовок и описание. Если Вы владеете аккаунтом создателя референдума, то заполните информацию о референдуме на Polkassembly"; +"common.full.details" = "Техническая информация"; From 26db5f13c6dad4d1add63356f09f74712b4d9543 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 26 Oct 2022 12:23:12 +0500 Subject: [PATCH 102/229] fix separators --- .../ReferendumDetails/ReferendumDetailsViewLayout.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index c1ef48d90a..47c81e125f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -13,6 +13,7 @@ final class ReferendumDetailsViewLayout: UIView { let votingDetailsRow = ReferendumVotingStatusDetailsView() let dAppsTableView: StackTableView = .create { $0.cellHeight = 64.0 + $0.hasSeparators = false $0.contentInsets = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 8.0, right: 16.0) } From 604c1cb70403ef54d6dc992424b19056715b0634 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 26 Oct 2022 14:06:08 +0500 Subject: [PATCH 103/229] add timer --- .../ReferendumDetailsPresenter.swift | 75 +++++++++++++++++++ .../ReferendumDetailsProtocols.swift | 1 + .../ReferendumDetailsViewController.swift | 5 ++ .../ReferendumDetailsViewFactory.swift | 1 + .../View/ReferendumVotingStatusView.swift | 9 +-- .../View/Rows/TimelineRow.swift | 4 + .../Timeline/ReferendumTimelineView.swift | 20 +++++ .../Referendums/ReferendumsPresenter.swift | 4 + 8 files changed, 112 insertions(+), 7 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 107857b675..c5e6e4898d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -15,6 +15,7 @@ final class ReferendumDetailsPresenter { let referendumTimelineViewModelFactory: ReferendumTimelineViewModelFactoryProtocol let referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol let displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol + let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol let chain: ChainModel let logger: LoggerProtocol @@ -31,6 +32,10 @@ final class ReferendumDetailsPresenter { private lazy var iconGenerator = PolkadotIconGenerator() + private var maxStatusTimeInterval: TimeInterval? + private var countdownTimer: CountdownTimer? + private var statusViewModel: StatusTimeViewModel? + init( referendum: ReferendumLocal, chain: ChainModel, @@ -42,6 +47,7 @@ final class ReferendumDetailsPresenter { referendumStringsFactory: ReferendumDisplayStringFactoryProtocol, referendumTimelineViewModelFactory: ReferendumTimelineViewModelFactoryProtocol, referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol, + statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol, displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol @@ -54,6 +60,7 @@ final class ReferendumDetailsPresenter { self.referendumFormatter = referendumFormatter self.referendumTimelineViewModelFactory = referendumTimelineViewModelFactory self.referendumMetadataViewModelFactory = referendumMetadataViewModelFactory + self.statusViewModelFactory = statusViewModelFactory self.displayAddressViewModelFactory = displayAddressViewModelFactory self.referendum = referendum self.chain = chain @@ -61,6 +68,10 @@ final class ReferendumDetailsPresenter { self.localizationManager = localizationManager } + deinit { + invalidateTimer() + } + private func provideReferendumInfoViewModel() { let referendumIndex = referendumFormatter.value(for: selectedLocale).string( from: referendum.index as NSNumber @@ -248,6 +259,55 @@ final class ReferendumDetailsPresenter { provideTimelineViewModel() provideFullDetailsViewModel() } + + private func invalidateTimer() { + countdownTimer?.delegate = nil + countdownTimer?.stop() + countdownTimer = nil + } + + private func updateTimerIfNeeded() { + guard + let blockTime = blockTime, + let blockNumber = blockNumber else { + return + } + + let activeTimeModel = statusViewModelFactory.createTimeViewModel( + for: referendum, + currentBlock: blockNumber, + blockDuration: blockTime, + locale: selectedLocale + ) + + guard let timeInterval = activeTimeModel?.timeInterval else { + invalidateTimer() + view?.didReceive(activeTimeViewModel: activeTimeModel?.viewModel) + return + } + + guard maxStatusTimeInterval != timeInterval else { + return + } + + maxStatusTimeInterval = timeInterval + statusViewModel = activeTimeModel + + countdownTimer = CountdownTimer() + countdownTimer?.delegate = self + countdownTimer?.start(with: timeInterval) + } + + private func updateTimerDisplay() { + guard + let remainedTimeInterval = countdownTimer?.remainedInterval, + let statusViewModel = statusViewModel, + let updatedViewModel = statusViewModel.updateModelClosure(remainedTimeInterval) else { + return + } + + view?.didReceive(activeTimeViewModel: updatedViewModel) + } } extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { @@ -342,6 +402,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol provideVotingDetails() provideTimelineViewModel() + updateTimerIfNeeded() } func didReceiveDApps(_ dApps: [GovernanceDApp]) { @@ -378,6 +439,20 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol } } +extension ReferendumDetailsPresenter: CountdownTimerDelegate { + func didStart(with _: TimeInterval) { + updateTimerDisplay() + } + + func didCountdown(remainedInterval _: TimeInterval) { + updateTimerDisplay() + } + + func didStop(with _: TimeInterval) { + updateTimerDisplay() + } +} + extension ReferendumDetailsPresenter: Localizable { func applyLocalization() { if let view = view, view.isSetup { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index ea860a5a17..4402ddffb2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -6,6 +6,7 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { func didReceive(yourVoteModel: YourVoteRow.Model?) func didReceive(requestedAmount: RequestedAmountRow.Model?) func didReceive(trackTagsModel: TrackTagsView.Model?) + func didReceive(activeTimeViewModel: ReferendumInfoView.Model.Time?) func didReceive(shouldHideFullDetails: Bool) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 400a21e124..e24c8aafac 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -150,4 +150,9 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { func didReceive(shouldHideFullDetails: Bool) { rootView.setFullDetails(hidden: shouldHideFullDetails, locale: localizationManager.selectedLocale) } + + func didReceive(activeTimeViewModel: ReferendumInfoView.Model.Time?) { + rootView.votingDetailsRow.statusView.bind(timeModel: activeTimeViewModel) + rootView.timelineView.bind(activeTimeViewModel: activeTimeViewModel) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index d7d98f6c93..65f06e2dfc 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -58,6 +58,7 @@ struct ReferendumDetailsViewFactory { referendumStringsFactory: referendumStringFactory, referendumTimelineViewModelFactory: timelineViewModelFactory, referendumMetadataViewModelFactory: metadataViewModelFactory, + statusViewModelFactory: statusViewModelFactory, displayAddressViewModelFactory: DisplayAddressViewModelFactory(), localizationManager: localizationManager, logger: Logger.shared diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift index c1323c07d0..02ecdc16a8 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift @@ -45,15 +45,10 @@ final class ReferendumVotingStatusView: UIView { extension ReferendumVotingStatusView { struct Model { let status: Status - let time: Time? + let time: ReferendumInfoView.Model.Time? let title: String? } - struct Time: Equatable { - let titleIcon: TitleIconViewModel - let isUrgent: Bool - } - struct Status { let name: String let kind: StatusKind @@ -91,7 +86,7 @@ extension ReferendumVotingStatusView { } } - func bind(timeModel: Time?) { + func bind(timeModel: ReferendumInfoView.Model.Time?) { if let time = timeModel { timeView.bind(viewModel: time.titleIcon) timeView.apply(style: time.isUrgent ? .activeTimeView : .timeView) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift index 25edd16e93..a62f1e85d1 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift @@ -30,6 +30,10 @@ final class TimelineRow: RoundedView, BindableView { contentView.bind(viewModel: viewModel) } + func bind(activeTimeViewModel: ReferendumInfoView.Model.Time?) { + contentView.bind(activeTimeViewModel: activeTimeViewModel) + } + private func setupLayout() { let content = UIView.vStack( spacing: 16, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift index bf47a6f6fa..f14ca76221 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift @@ -113,6 +113,26 @@ extension ReferendumTimelineView: BindableView { updateStatuses(model: viewModel) setNeedsLayout() } + + func bind(activeTimeViewModel: ReferendumInfoView.Model.Time?) { + guard let activeView = statusViews.last as? GenericMultiValueView else { + return + } + + if let activeTimeViewModel = activeTimeViewModel { + if activeTimeViewModel.isUrgent { + activeView.valueBottom.detailsLabel.apply(style: UILabel.Style.timelineUrgentSubtitle) + } else { + activeView.valueBottom.detailsLabel.apply(style: UILabel.Style.timelineNeutralSubtitle) + } + + activeView.valueBottom.bind(viewModel: activeTimeViewModel.titleIcon) + } else { + activeView.valueBottom.bind(viewModel: nil) + } + + setNeedsLayout() + } } private extension UILabel.Style { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index badaa0369a..62087415d5 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -26,6 +26,10 @@ final class ReferendumsPresenter { private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() + deinit { + invalidateTimer() + } + init( interactor: ReferendumsInteractorInputProtocol, wireframe: ReferendumsWireframeProtocol, From 2f3b66d52861aa558aef288b8a148ba38ffcfb13 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 27 Oct 2022 22:58:16 +0500 Subject: [PATCH 104/229] add full details --- novawallet.xcodeproj/project.pbxproj | 12 + .../Governance/Model/ReferendumLocal.swift | 32 +- .../Operation/Gov2LocalMappingFactory.swift | 50 ++- .../ReferendumDetailsPresenter.swift | 15 +- .../ReferendumDetailsViewLayout.swift | 2 +- .../ReferendumFullDetailsInteractor.swift | 44 ++- .../ReferendumFullDetailsPresenter.swift | 195 ++++++------ .../ReferendumFullDetailsProtocols.swift | 30 +- .../ReferendumFullDetailsViewController.swift | 77 +++-- .../ReferendumFullDetailsViewFactory.swift | 29 +- .../ReferendumFullDetailsViewLayout.swift | 291 +++++++++++------- .../ReferendumStateLocal+Presenter.swift | 4 +- .../ReferendumFullDetailsViewModel.swift | 19 ++ .../ReferendumTimelineViewModelFactory.swift | 12 +- novawallet/en.lproj/Localizable.strings | 10 +- novawallet/ru.lproj/Localizable.strings | 10 +- 16 files changed, 531 insertions(+), 301 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDetails/ViewModel/ReferendumFullDetailsViewModel.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 6390eadf28..b05f8031c1 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1599,6 +1599,7 @@ 84A58FD928A10ABD003F6ABF /* MultipartQrOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A58FD828A10ABD003F6ABF /* MultipartQrOperationFactory.swift */; }; 84A6171B2625AC3E007B75E1 /* CallCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A6171A2625AC3E007B75E1 /* CallCodingPath.swift */; }; 84A617262625AF51007B75E1 /* RuntimeMetadata+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A617252625AF51007B75E1 /* RuntimeMetadata+Internal.swift */; }; + 84A6AB5E290AA7DF001B57B2 /* ReferendumFullDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A6AB5D290AA7DF001B57B2 /* ReferendumFullDetailsViewModel.swift */; }; 84A8FD8E265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A8FD8D265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift */; }; 84A90489288EA0E500DFC8E2 /* NoKeysCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A90488288EA0E500DFC8E2 /* NoKeysCommand.swift */; }; 84AA004326C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AA004226C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift */; }; @@ -4528,6 +4529,7 @@ 84A58FD828A10ABD003F6ABF /* MultipartQrOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipartQrOperationFactory.swift; sourceTree = ""; }; 84A6171A2625AC3E007B75E1 /* CallCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallCodingPath.swift; sourceTree = ""; }; 84A617252625AF51007B75E1 /* RuntimeMetadata+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuntimeMetadata+Internal.swift"; sourceTree = ""; }; + 84A6AB5D290AA7DF001B57B2 /* ReferendumFullDetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsViewModel.swift; sourceTree = ""; }; 84A8FD8D265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmData.swift; sourceTree = ""; }; 84A90488288EA0E500DFC8E2 /* NoKeysCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoKeysCommand.swift; sourceTree = ""; }; 84AA004226C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeSyncServiceTests.swift; sourceTree = ""; }; @@ -10273,6 +10275,14 @@ path = Operation; sourceTree = ""; }; + 84A6AB5C290AA7C8001B57B2 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 84A6AB5D290AA7DF001B57B2 /* ReferendumFullDetailsViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; 84A8FD8C265FDA42002ADB58 /* Model */ = { isa = PBXGroup; children = ( @@ -12197,6 +12207,7 @@ 872D923BC3CE0F69157DB2EA /* ReferendumFullDetails */ = { isa = PBXGroup; children = ( + 84A6AB5C290AA7C8001B57B2 /* ViewModel */, 3F6DA24E0481A3678F2EF809 /* ReferendumFullDetailsProtocols.swift */, C80D934D47929D2331111AD7 /* ReferendumFullDetailsWireframe.swift */, 33DFAA0EEEA7F99C6D1CF4B1 /* ReferendumFullDetailsPresenter.swift */, @@ -16631,6 +16642,7 @@ 84C342092831645800156569 /* EraCountdownDisplay.swift in Sources */, 841E5551282E2C1700C8438F /* StakingParachainInteractor+Subscription.swift in Sources */, F0B74A766BF50518323AB25C /* DAppAuthConfirmWireframe.swift in Sources */, + 84A6AB5E290AA7DF001B57B2 /* ReferendumFullDetailsViewModel.swift in Sources */, 575A729D07A6B984851E6DD0 /* DAppAuthConfirmPresenter.swift in Sources */, 846E501527799B3E0049B659 /* DAppAuthViewModelFactory.swift in Sources */, 3086C94FE01CDFC4F79A9D7F /* DAppAuthConfirmViewController.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 719816f2e4..5603f07d7c 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -44,6 +44,25 @@ struct ReferendumLocal { return nil } } + + var deposit: BigUInt? { + switch state { + case let .preparing(model): + return model.deposit + case let .deciding(model): + return model.deposit + case let .approved(model): + return model.deposit + case let .rejected(model): + return model.deposit + case let .cancelled(model): + return model.deposit + case let .timedOut(model): + return model.deposit + case .killed, .executed: + return nil + } + } } struct SupportAndVotesLocal { @@ -103,6 +122,7 @@ enum ReferendumStateLocal { let since: BlockNumber let period: Moment let confirmationUntil: BlockNumber? + let deposit: BigUInt? var rejectedAt: BlockNumber { since + period @@ -131,14 +151,20 @@ enum ReferendumStateLocal { struct Approved { let since: BlockNumber let whenEnactment: BlockNumber? + let deposit: BigUInt? + } + + struct NotApproved { + let atBlock: BlockNumber + let deposit: BigUInt? } case preparing(model: Preparing) case deciding(model: Deciding) case approved(model: Approved) - case rejected(atBlock: Moment) - case cancelled(atBlock: Moment) - case timedOut(atBlock: Moment) + case rejected(model: NotApproved) + case cancelled(model: NotApproved) + case timedOut(model: NotApproved) case killed(atBlock: Moment) case executed diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index 6eb5dee6e2..b1eb427447 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -1,4 +1,5 @@ import Foundation +import BigInt final class Gov2LocalMappingFactory { private func createDecidingState( @@ -30,6 +31,8 @@ final class Gov2LocalMappingFactory { let localTrack = GovernanceTrackLocal(trackId: status.track, name: track.name) + let deposit = deposit(from: status.submissionDeposit, decision: status.decisionDeposit) + let model = ReferendumStateLocal.Deciding( track: localTrack, proposal: status.proposal, @@ -37,7 +40,8 @@ final class Gov2LocalMappingFactory { submitted: status.submitted, since: deciding.since, period: track.decisionPeriod, - confirmationUntil: deciding.confirming + confirmationUntil: deciding.confirming, + deposit: deposit ) return .deciding(model: model) @@ -114,6 +118,7 @@ final class Gov2LocalMappingFactory { return ReferendumLocal(index: UInt(index), state: state, proposer: status.submissionDeposit.who) } + // swiftlint:disable:next function_body_length func mapRemote( referendum: ReferendumInfo, index: Referenda.ReferendumIndex, @@ -127,7 +132,11 @@ final class Gov2LocalMappingFactory { let state: ReferendumStateLocal if let enactmentBlock = enactmentBlock { - let value = ReferendumStateLocal.Approved(since: status.since, whenEnactment: enactmentBlock) + let value = ReferendumStateLocal.Approved( + since: status.since, + whenEnactment: enactmentBlock, + deposit: deposit(from: status.submissionDeposit, decision: status.decisionDeposit) + ) state = .approved(model: value) } else { state = .executed @@ -139,21 +148,39 @@ final class Gov2LocalMappingFactory { proposer: status.submissionDeposit.who ) case let .rejected(status): + let value = notApproved( + from: status.since, + submission: status.submissionDeposit, + decision: status.decisionDeposit + ) + return ReferendumLocal( index: UInt(index), - state: .rejected(atBlock: status.since), + state: .rejected(model: value), proposer: status.submissionDeposit.who ) case let .timedOut(status): + let value = notApproved( + from: status.since, + submission: status.submissionDeposit, + decision: status.decisionDeposit + ) + return ReferendumLocal( index: UInt(index), - state: .timedOut(atBlock: status.since), + state: .timedOut(model: value), proposer: status.submissionDeposit.who ) case let .cancelled(status): + let value = notApproved( + from: status.since, + submission: status.submissionDeposit, + decision: status.decisionDeposit + ) + return ReferendumLocal( index: UInt(index), - state: .cancelled(atBlock: status.since), + state: .cancelled(model: value), proposer: status.submissionDeposit.who ) case let .killed(atBlock): @@ -162,4 +189,17 @@ final class Gov2LocalMappingFactory { return nil } } + + private func deposit(from submission: Referenda.Deposit, decision: Referenda.Deposit?) -> BigUInt { + submission.amount + (decision?.amount ?? 0) + } + + private func notApproved( + from atBlock: BlockNumber, + submission: Referenda.Deposit, + decision: Referenda.Deposit? + ) -> ReferendumStateLocal.NotApproved { + let deposit = deposit(from: submission, decision: decision) + return .init(atBlock: atBlock, deposit: deposit) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index c5e6e4898d..af5091cc3f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -245,7 +245,7 @@ final class ReferendumDetailsPresenter { } private func provideFullDetailsViewModel() { - let shouldHide = actionDetails == nil && referendumMetadata == nil + let shouldHide = actionDetails == nil view?.didReceive(shouldHideFullDetails: shouldHide) } @@ -343,7 +343,18 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { func readFullDescription() {} - func openFullDetails() {} + func openFullDetails() { + guard let actionDetails = actionDetails else { + return + } + + wireframe.showFullDetails( + from: view, + referendum: referendum, + actionDetails: actionDetails, + identities: identities ?? [:] + ) + } } extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index 47c81e125f..b79f7c8f78 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -132,7 +132,7 @@ final class ReferendumDetailsViewLayout: UIView { func setFullDetails(hidden: Bool, locale: Locale) { fullDetailsView.isHidden = hidden - fullDetailsView.bind(title: R.string.localizable.commonFullDetails(preferredLanguages: locale.rLanguages)) + fullDetailsView.bind(title: R.string.localizable.govFullDetails(preferredLanguages: locale.rLanguages)) } private func createHeader(with text: String) -> StackTableHeaderCell { diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift index 133b5f183a..47540e81de 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift @@ -29,6 +29,9 @@ final class ReferendumFullDetailsInteractor { } private func makeSubscriptions() { + priceProvider?.removeObserver(self) + priceProvider = nil + guard let priceId = chain.utilityAsset()?.priceId else { return } @@ -38,28 +41,29 @@ final class ReferendumFullDetailsInteractor { private func formatJSON() { guard let call = referendumAction.call else { - presenter?.didReceive(error: .emptyJSON) + presenter?.didReceive(json: nil) return } - let processingOperation = processingOperationFactory.createProcessingOperation(for: call.args) - processingOperation.completionBlock = { [weak self] in - guard let self = self else { - return - } - do { - let result = try processingOperation.extractNoCancellableResultData() - DispatchQueue.main.async { - self.presenter?.didReceive(json: result) - } - } catch { + + do { + let json = try call.toScaleCompatibleJSON() + + let processingOperation = processingOperationFactory.createProcessingOperation(for: json) + processingOperation.completionBlock = { [weak self] in DispatchQueue.main.async { - self.presenter?.didReceive(json: nil) - self.presenter?.didReceive(error: .processingJSON(error)) + do { + let result = try processingOperation.extractNoCancellableResultData() + self?.presenter?.didReceive(json: result) + } catch { + self?.presenter?.didReceive(error: .processingJSON(error)) + } } } - } - operationQueue.addOperation(processingOperation) + operationQueue.addOperation(processingOperation) + } catch { + presenter?.didReceive(error: .processingJSON(error)) + } } } @@ -68,6 +72,14 @@ extension ReferendumFullDetailsInteractor: ReferendumFullDetailsInteractorInputP makeSubscriptions() formatJSON() } + + func remakeSubscriptions() { + makeSubscriptions() + } + + func refreshCall() { + formatJSON() + } } extension ReferendumFullDetailsInteractor: PriceLocalSubscriptionHandler, PriceLocalStorageSubscriber { diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index f3cc10b01c..a6b39fa146 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -1,33 +1,35 @@ import Foundation import SubstrateSdk import SoraFoundation +import BigInt final class ReferendumFullDetailsPresenter { weak var view: ReferendumFullDetailsViewProtocol? let wireframe: ReferendumFullDetailsWireframeProtocol let interactor: ReferendumFullDetailsInteractorInputProtocol - let chainIconGenerator: IconGenerating - let priceAssetInfoFactory: PriceAssetInfoFactoryProtocol - let assetFormatterFactory: AssetBalanceFormatterFactoryProtocol + let balanceViewModelFactory: BalanceViewModelFactoryProtocol + let addressViewModelFactory: DisplayAddressViewModelFactoryProtocol + let logger: LoggerProtocol let chain: ChainModel let referendum: ReferendumLocal let actionDetails: ReferendumActionLocal let identities: [AccountAddress: AccountIdentity] + private var price: PriceData? private var json: String? init( interactor: ReferendumFullDetailsInteractorInputProtocol, wireframe: ReferendumFullDetailsWireframeProtocol, - chainIconGenerator: IconGenerating, chain: ChainModel, referendum: ReferendumLocal, actionDetails: ReferendumActionLocal, identities: [AccountAddress: AccountIdentity], + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + addressViewModelFactory: DisplayAddressViewModelFactoryProtocol, localizationManager: LocalizationManagerProtocol, - currencyManager: CurrencyManagerProtocol, - assetFormatterFactory: AssetBalanceFormatterFactory + logger: LoggerProtocol ) { self.interactor = interactor self.wireframe = wireframe @@ -35,126 +37,88 @@ final class ReferendumFullDetailsPresenter { self.referendum = referendum self.actionDetails = actionDetails self.identities = identities - self.chainIconGenerator = chainIconGenerator - priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) - self.assetFormatterFactory = assetFormatterFactory - self.currencyManager = currencyManager + self.logger = logger + self.balanceViewModelFactory = balanceViewModelFactory + self.addressViewModelFactory = addressViewModelFactory self.localizationManager = localizationManager } - private func updateView() { - guard let view = view else { - return - } - getProposer().map { - view.didReceive(proposerModel: .init( - title: "Proposer", - model: .init( - details: $0.name, - imageViewModel: $0.icon - ) - )) - } - let approvalCurveModel = referendum.state.approvalCurve.map { - TitleWithSubtitleViewModel( - title: "Approve Curve", - subtitle: $0.displayName - ) - } - let supportCurveModel = referendum.state.supportCurve.map { - TitleWithSubtitleViewModel( - title: "Support Curve", - subtitle: $0.displayName - ) - } - let callHashModel = referendum.state.callHash.map { - TitleWithSubtitleViewModel( - title: "Call Hash", - subtitle: $0 - ) + private func getAccountViewModel(_ accountId: AccountId?) -> DisplayAddressViewModel? { + guard let accountId = accountId, + let address = try? accountId.toAddress(using: chain.chainFormat) else { + return nil } - view.didReceive( - approveCurve: approvalCurveModel, - supportCurve: supportCurveModel, - callHash: callHashModel + let displayAddress = DisplayAddress( + address: address, + username: identities[address]?.displayName ?? "" ) - updatePriceDependentViews() + return addressViewModelFactory.createViewModel(from: displayAddress) } - private func getProposer() -> (name: String, icon: ImageViewModelProtocol?)? { - guard let proposer = referendum.proposer, - let proposerAddress = try? proposer.toAddress(using: chain.chainFormat) else { + private func getBalanceViewModel(_ amount: BigUInt?, locale: Locale) -> BalanceViewModelProtocol? { + guard + let amount = amount, + let assetInfo = chain.utilityAsset()?.displayInfo, + let amountDecimal = Decimal.fromSubstrateAmount(amount, precision: assetInfo.assetPrecision) else { return nil } - let chainAccountIcon = icon( - generator: chainIconGenerator, - from: proposer - ) - - let name = identities[proposerAddress]?.displayName ?? proposerAddress - - return (name: name, icon: chainAccountIcon) + return balanceViewModelFactory.balanceFromPrice( + amountDecimal, + priceData: price + ).value(for: locale) } - private func icon( - generator: IconGenerating, - from imageData: Data? - ) -> DrawableIconViewModel? { - guard let data = imageData, - let icon = try? generator.generateFromAccountId(data) else { - return nil + private func provideProposerViewModel() { + guard let proposer = getAccountViewModel(referendum.proposer) else { + view?.didReceive(proposer: nil) + return } - return DrawableIconViewModel(icon: icon) + let deposit = getBalanceViewModel(referendum.deposit, locale: selectedLocale) + view?.didReceive(proposer: .init(proposer: proposer, deposit: deposit)) } - private func updatePriceDependentViews() { - guard let utilityAsset = chain.utilityAsset() else { + private func provideBeneficiaryViewModel() { + guard + let beneficiary = getAccountViewModel( + actionDetails.amountSpendDetails?.beneficiary.accountId + ), + let amount = getBalanceViewModel( + actionDetails.amountSpendDetails?.amount, + locale: selectedLocale + ) else { + view?.didReceive(beneficiary: nil) return } - guard let amountInPlank = actionDetails.amountSpendDetails?.amount else { + + view?.didReceive(beneficiary: .init(account: beneficiary, amount: amount)) + } + + private func provideCurveAndHashViewModel() { + guard + let approvalCurve = referendum.state.approvalCurve, + let supportCurve = referendum.state.supportCurve else { return } - let amount = Decimal.fromSubstrateAmount( - amountInPlank, - precision: Int16(utilityAsset.precision) - ) ?? 0.0 - - let formattedAmount = formatAmount( - amount, - assetDisplayInfo: utilityAsset.displayInfo, - locale: selectedLocale - ) - let price = formatPrice(amount: amount, priceData: price, locale: selectedLocale) - view?.didReceive( - deposit: .init( - topValue: formattedAmount, - bottomValue: price - ), - title: "Deposit" + + let callHash = referendum.state.callHash + + let model = ReferendumFullDetailsViewModel.CurveAndHash( + approveCurve: approvalCurve.displayName, + supportCurve: supportCurve.displayName, + callHash: callHash ) - } - private func formatPrice(amount: Decimal, priceData: PriceData?, locale: Locale) -> String { - guard let currencyManager = currencyManager else { - return "" - } - let currencyId = priceData?.currencyId ?? currencyManager.selectedCurrency.id - let assetDisplayInfo = priceAssetInfoFactory.createAssetBalanceDisplayInfo(from: currencyId) - let priceFormatter = assetFormatterFactory.createTokenFormatter(for: assetDisplayInfo) - return priceFormatter.value(for: locale).stringFromDecimal(amount) ?? "" + view?.didReceive(params: model) } - private func formatAmount( - _ amount: Decimal, - assetDisplayInfo: AssetBalanceDisplayInfo, - locale: Locale - ) -> String { - let priceFormatter = assetFormatterFactory.createTokenFormatter(for: assetDisplayInfo) - return priceFormatter.value(for: locale).stringFromDecimal(amount) ?? "" + private func updateView() { + provideProposerViewModel() + provideBeneficiaryViewModel() + provideCurveAndHashViewModel() } } @@ -163,20 +127,39 @@ extension ReferendumFullDetailsPresenter: ReferendumFullDetailsPresenterProtocol interactor.setup() updateView() } + + func presentProposer() {} + + func presentBeneficiary() {} + + func presentCallHash() {} } extension ReferendumFullDetailsPresenter: ReferendumFullDetailsInteractorOutputProtocol { func didReceive(price: PriceData?) { self.price = price - updatePriceDependentViews() + + provideProposerViewModel() + provideBeneficiaryViewModel() } func didReceive(json: String?) { - view?.didReceive(json: json, jsonTitle: "Parameters JSON") + view?.didReceive(json: json) } func didReceive(error: ReferendumFullDetailsError) { - print("Received error: \(error.localizedDescription)") + logger.error("Did receiver error: \(error)") + + switch error { + case .priceFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + case .processingJSON: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refreshCall() + } + } } } @@ -187,9 +170,3 @@ extension ReferendumFullDetailsPresenter: Localizable { } } } - -extension ReferendumFullDetailsPresenter: SelectedCurrencyDepending { - func applyCurrency() { - updatePriceDependentViews() - } -} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift index 0c764d8363..d0e7b2f00f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift @@ -1,17 +1,21 @@ protocol ReferendumFullDetailsViewProtocol: ControllerBackedProtocol { - func didReceive(proposerModel: ProposerTableCell.Model?) - func didReceive(json: String?, jsonTitle: String) - func didReceive(amountSpendDetails: AmountSpendDetailsTableView.Model?) - func didReceive(deposit: MultiValueView.Model, title: String) - func didReceive( - approveCurve: TitleWithSubtitleViewModel?, - supportCurve: TitleWithSubtitleViewModel?, - callHash: TitleWithSubtitleViewModel? - ) + func didReceive(proposer: ReferendumFullDetailsViewModel.Proposer?) + func didReceive(beneficiary: ReferendumFullDetailsViewModel.Beneficiary?) + func didReceive(params: ReferendumFullDetailsViewModel.CurveAndHash?) + func didReceive(json: String?) } protocol ReferendumFullDetailsPresenterProtocol: AnyObject { func setup() + func presentProposer() + func presentBeneficiary() + func presentCallHash() +} + +protocol ReferendumFullDetailsInteractorInputProtocol: AnyObject { + func setup() + func remakeSubscriptions() + func refreshCall() } protocol ReferendumFullDetailsInteractorOutputProtocol: AnyObject { @@ -20,14 +24,10 @@ protocol ReferendumFullDetailsInteractorOutputProtocol: AnyObject { func didReceive(error: ReferendumFullDetailsError) } -protocol ReferendumFullDetailsWireframeProtocol: AnyObject {} - -protocol ReferendumFullDetailsInteractorInputProtocol: AnyObject { - func setup() -} +protocol ReferendumFullDetailsWireframeProtocol: ErrorPresentable, AlertPresentable, AddressOptionsPresentable, + CommonRetryable {} enum ReferendumFullDetailsError: Error { case priceFailed(Error) - case emptyJSON case processingJSON(Error) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift index b942ac3877..19a05da6db 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift @@ -1,13 +1,16 @@ import UIKit +import SoraFoundation final class ReferendumFullDetailsViewController: UIViewController, ViewHolder { typealias RootViewType = ReferendumFullDetailsViewLayout let presenter: ReferendumFullDetailsPresenterProtocol - init(presenter: ReferendumFullDetailsPresenterProtocol) { + init(presenter: ReferendumFullDetailsPresenterProtocol, localizationManager: LocalizationManagerProtocol) { self.presenter = presenter super.init(nibName: nil, bundle: nil) + + self.localizationManager = localizationManager } @available(*, unavailable) @@ -22,40 +25,68 @@ final class ReferendumFullDetailsViewController: UIViewController, ViewHolder { override func viewDidLoad() { super.viewDidLoad() + setupLocalization() + presenter.setup() } + + private func setupLocalization() { + title = R.string.localizable.govFullDetails(preferredLanguages: selectedLocale.rLanguages) + } + + @objc private func actionProposer() { + presenter.presentProposer() + } + + @objc private func actionBeneficiary() { + presenter.presentBeneficiary() + } + + @objc private func actionCallHash() { + presenter.presentCallHash() + } } extension ReferendumFullDetailsViewController: ReferendumFullDetailsViewProtocol { - func didReceive(proposerModel: ProposerTableCell.Model?) { - rootView.updateProposerCell(proposerModel: proposerModel) + func didReceive(proposer: ReferendumFullDetailsViewModel.Proposer?) { + rootView.setProposer(viewModel: proposer, locale: selectedLocale) + + rootView.proposerCell?.addTarget( + self, + action: #selector(actionProposer), + for: .touchUpInside + ) } - func didReceive(json: String?, jsonTitle: String) { - if let json = json { - rootView.jsonView.view.text = json - } else { - // todo - } - rootView.jsonTitle.text = jsonTitle + func didReceive(beneficiary: ReferendumFullDetailsViewModel.Beneficiary?) { + rootView.setBeneficiary(viewModel: beneficiary, locale: selectedLocale) + + rootView.beneficiaryCell?.addTarget( + self, + action: #selector(actionBeneficiary), + for: .touchUpInside + ) } - func didReceive( - approveCurve: TitleWithSubtitleViewModel?, - supportCurve: TitleWithSubtitleViewModel?, - callHash: TitleWithSubtitleViewModel? - ) { - rootView.update(approveCurveModel: approveCurve) - rootView.update(supportCurveModel: supportCurve) - rootView.update(callHashModel: callHash) + func didReceive(params: ReferendumFullDetailsViewModel.CurveAndHash?) { + rootView.setCurveAndHash(viewModel: params, locale: selectedLocale) + + rootView.callHashCell?.addTarget( + self, + action: #selector(actionCallHash), + for: .touchUpInside + ) } - func didReceive(amountSpendDetails: AmountSpendDetailsTableView.Model?) { - rootView.update(amountSpendDetails: amountSpendDetails) + func didReceive(json: String?) { + rootView.setJson(viewModel: json, locale: selectedLocale) } +} - func didReceive(deposit: MultiValueView.Model, title: String) { - rootView.depositTableCell.titleLabel.text = title - rootView.depositTableCell.rowContentView.valueView.bind(viewModel: deposit) +extension ReferendumFullDetailsViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + setupLocalization() + } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift index f1c463e4f9..64b2c90c38 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift @@ -9,8 +9,10 @@ struct ReferendumFullDetailsViewFactory { actionDetails: ReferendumActionLocal, identities: [AccountAddress: AccountIdentity] ) -> ReferendumFullDetailsViewProtocol? { - guard let chain = state.settings.value, - let currencyManager = CurrencyManager.shared else { + guard + let chain = state.settings.value, + let currencyManager = CurrencyManager.shared, + let assetInfo = chain.utilityAssetDisplayInfo() else { return nil } @@ -25,20 +27,33 @@ struct ReferendumFullDetailsViewFactory { referendumAction: actionDetails, operationQueue: OperationManagerFacade.sharedDefaultQueue ) + + let localizationManager = LocalizationManager.shared + + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: assetInfo, + priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) + ) + let presenter = ReferendumFullDetailsPresenter( interactor: interactor, wireframe: wireframe, - chainIconGenerator: PolkadotIconGenerator(), chain: chain, referendum: referendum, actionDetails: actionDetails, identities: identities, - localizationManager: LocalizationManager.shared, - currencyManager: currencyManager, - assetFormatterFactory: AssetBalanceFormatterFactory() + balanceViewModelFactory: balanceViewModelFactory, + addressViewModelFactory: DisplayAddressViewModelFactory(), + localizationManager: localizationManager, + logger: Logger.shared ) + interactor.presenter = presenter - let view = ReferendumFullDetailsViewController(presenter: presenter) + + let view = ReferendumFullDetailsViewController( + presenter: presenter, + localizationManager: localizationManager + ) presenter.view = view diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index 9c7655229e..8fc8234fd4 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -3,33 +3,21 @@ import UIKit final class ReferendumFullDetailsViewLayout: UIView { let containerView: ScrollableContainerView = { let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) - view.stackView.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 24, right: 16) + view.stackView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 24, right: 16) view.stackView.isLayoutMarginsRelativeArrangement = true view.stackView.alignment = .fill return view }() - let accountDetailsTableView = StackTableView() - var referendumDetailsTableView = StackTableView() - var amountSpendDetailsTableView: AmountSpendDetailsTableView? - lazy var beneficiaryTableCell = StackInfoTableCell() - lazy var requestedAmountTableCell = StackTitleMultiValueCell() - - var proposerTableCell: StackInfoTableCell? - let depositTableCell = StackTitleMultiValueCell() - - var approveCurve: StackTableCell? - var supportCurve: StackTableCell? - var callHash: StackInfoTableCell? - - let jsonTitle: UILabel = .init(style: .caption1White64) - let jsonView: BlurredView = .create { - $0.view.allowsEditingTextAttributes = false - $0.view.isScrollEnabled = false - $0.view.backgroundColor = .clear - $0.view.textAlignment = .left - $0.contentInsets = .zero - } + private(set) var proposerTableView: StackTableView? + private(set) var beneficiaryTableView: StackTableView? + private(set) var curveAndHashTableView: StackTableView? + + private(set) var proposerCell: StackInfoTableCell? + private(set) var beneficiaryCell: StackInfoTableCell? + private(set) var callHashCell: StackInfoTableCell? + + private(set) var jsonView: UIView? override init(frame: CGRect) { super.init(frame: frame) @@ -47,119 +35,202 @@ final class ReferendumFullDetailsViewLayout: UIView { containerView.snp.makeConstraints { $0.edges.equalToSuperview() } - - containerView.stackView.spacing = 8 - containerView.stackView.addArrangedSubview(accountDetailsTableView) - containerView.stackView.addArrangedSubview(referendumDetailsTableView) - accountDetailsTableView.addArrangedSubview(depositTableCell) - containerView.stackView.addArrangedSubview(jsonTitle) - containerView.stackView.addArrangedSubview(jsonView) } - func updateProposerCell(proposerModel: ProposerTableCell.Model?) { - guard let proposerModel = proposerModel else { - proposerTableCell?.removeFromSuperview() - proposerTableCell = nil - return - } - if proposerTableCell == nil { - let proposerTableCell = createStackInfoCell(title: proposerModel.title) - accountDetailsTableView.insertArrangedSubview(proposerTableCell, at: 0) - self.proposerTableCell = proposerTableCell + func setProposer(viewModel: ReferendumFullDetailsViewModel.Proposer?, locale: Locale) { + proposerTableView?.clear() + proposerCell = nil + + if let viewModel = viewModel { + if proposerTableView == nil { + let tableView = StackTableView() + containerView.stackView.insertArrangedSubview(tableView, at: 0) + proposerTableView = tableView + } + + let proposerCell = createAccountCell( + with: R.string.localizable.govProposer(preferredLanguages: locale.rLanguages), + viewModel: viewModel.proposer + ) + + proposerTableView?.addArrangedSubview(proposerCell) + + if let deposit = viewModel.deposit { + let depositCell = createBalanceCell( + with: R.string.localizable.govDeposit(preferredLanguages: locale.rLanguages), + viewModel: deposit + ) + proposerTableView?.addArrangedSubview(depositCell) + } + } else { + proposerTableView?.removeFromSuperview() + proposerTableView = nil } - proposerTableCell?.bind(viewModel: proposerModel.model) + updateLayout() } - func update(amountSpendDetails: AmountSpendDetailsTableView.Model?) { - guard let amountSpendDetails = amountSpendDetails else { - amountSpendDetailsTableView?.removeFromSuperview() - amountSpendDetailsTableView = nil - return - } - if amountSpendDetailsTableView == nil { - amountSpendDetailsTableView = .init() - accountDetailsTableView.addArrangedSubview(beneficiaryTableCell) - accountDetailsTableView.addArrangedSubview(requestedAmountTableCell) + func setBeneficiary(viewModel: ReferendumFullDetailsViewModel.Beneficiary?, locale: Locale) { + beneficiaryTableView?.clear() + beneficiaryCell = nil + + if let viewModel = viewModel { + if beneficiaryTableView == nil { + let tableView = StackTableView() + insertView(tableView, afterOneOf: [proposerTableView]) + beneficiaryTableView = tableView + } + + let beneficiaryCell = createAccountCell( + with: R.string.localizable.govBeneficiary(preferredLanguages: locale.rLanguages), + viewModel: viewModel.account + ) + + beneficiaryTableView?.addArrangedSubview(beneficiaryCell) + + if let amount = viewModel.amount { + let amountCell = createBalanceCell( + with: R.string.localizable.govRequestedAmount(preferredLanguages: locale.rLanguages), + viewModel: amount + ) + + beneficiaryTableView?.addArrangedSubview(amountCell) + } + } else { + beneficiaryTableView?.removeFromSuperview() + beneficiaryTableView = nil } - beneficiaryTableCell.titleLabel.text = amountSpendDetails.beneficiary.title - beneficiaryTableCell.bind(viewModel: amountSpendDetails.beneficiary.model) - requestedAmountTableCell.titleLabel.text = amountSpendDetails.requestedAmount.title - requestedAmountTableCell.rowContentView.valueView.bind(viewModel: amountSpendDetails.requestedAmount.model) + + updateLayout() } - func update(approveCurveModel: TitleWithSubtitleViewModel?) { - guard let model = approveCurveModel else { - approveCurve?.removeFromSuperview() - approveCurve = nil - return - } - if approveCurve == nil { - approveCurve = .init() - approveCurve.map(referendumDetailsTableView.addArrangedSubview) + func setCurveAndHash(viewModel: ReferendumFullDetailsViewModel.CurveAndHash?, locale: Locale) { + curveAndHashTableView?.clear() + curveAndHashTableView = nil + + if let viewModel = viewModel { + if curveAndHashTableView == nil { + let tableView = StackTableView() + insertView(tableView, afterOneOf: [beneficiaryTableView, proposerTableView]) + curveAndHashTableView = tableView + } + + let approveCurveCell = createTitleValueCell( + with: R.string.localizable.govApproveCurve(preferredLanguages: locale.rLanguages), + value: viewModel.approveCurve + ) + + curveAndHashTableView?.addArrangedSubview(approveCurveCell) + + let supportCurveCell = createTitleValueCell( + with: R.string.localizable.govSupportCurve(preferredLanguages: locale.rLanguages), + value: viewModel.supportCurve + ) + + curveAndHashTableView?.addArrangedSubview(supportCurveCell) + + if let callHash = viewModel.callHash { + let callHashCell = createInfoCell( + with: R.string.localizable.govCallHash(preferredLanguages: locale.rLanguages), + value: callHash + ) + + callHashCell.detailsLabel.lineBreakMode = .byTruncatingMiddle + + curveAndHashTableView?.addArrangedSubview(callHashCell) + self.callHashCell = callHashCell + } + } else { + curveAndHashTableView?.removeFromSuperview() + curveAndHashTableView = nil } - approveCurve?.titleLabel.text = model.title - approveCurve?.detailsLabel.text = model.subtitle + + updateLayout() } - func update(supportCurveModel: TitleWithSubtitleViewModel?) { - guard let model = supportCurveModel else { - supportCurve?.removeFromSuperview() - supportCurve = nil - return - } - if supportCurve == nil { - supportCurve = .init() - supportCurve.map(referendumDetailsTableView.addArrangedSubview) + func setJson(viewModel: String?, locale: Locale) { + jsonView?.removeFromSuperview() + jsonView = nil + + if let viewModel = viewModel { + let jsonView: GenericMultiValueView> = .create { + $0.valueTop.apply(style: .caption1White64) + $0.valueTop.textAlignment = .left + $0.spacing = 12.0 + + let textView = $0.valueBottom.view + textView.isEditable = false + textView.textContainerInset = .zero + textView.textContainer.lineFragmentPadding = 0 + textView.isScrollEnabled = false + textView.backgroundColor = .clear + textView.textAlignment = .left + + $0.valueBottom.contentInsets = .zero + $0.valueBottom.innerInsets = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12) + } + + jsonView.valueTop.text = R.string.localizable.govParametersJson(preferredLanguages: locale.rLanguages) + + jsonView.valueBottom.view.text = viewModel + containerView.stackView.addArrangedSubview(jsonView) + + self.jsonView = jsonView } - supportCurve?.titleLabel.text = model.title - supportCurve?.detailsLabel.text = model.subtitle } - func update(callHashModel: TitleWithSubtitleViewModel?) { - guard let model = callHashModel else { - callHash?.removeFromSuperview() - callHash = nil - return - } - if callHash == nil { - callHash = .init() - callHash.map(referendumDetailsTableView.addArrangedSubview) + private func insertView(_ view: UIView, afterOneOf subviews: [UIView?]) { + if let optSubview = subviews.first(where: { $0 != nil }), let subview = optSubview { + containerView.stackView.insertArranged(view: view, after: subview) + } else { + containerView.stackView.insertArrangedSubview(view, at: 0) } - callHash?.titleLabel.text = model.title - callHash?.detailsLabel.text = model.subtitle } - private func createStackInfoCell(title: String) -> StackInfoTableCell { - let proposerCell = StackInfoTableCell() - proposerCell.rowContentView.valueView.mode = .iconDetails - proposerCell.rowContentView.titleView.text = title - return proposerCell + private func createAccountCell(with title: String, viewModel: DisplayAddressViewModel) -> StackInfoTableCell { + let cell = StackInfoTableCell() + cell.titleLabel.text = title + cell.detailsLabel.lineBreakMode = viewModel.lineBreakMode + cell.bind(viewModel: viewModel.cellViewModel) + return cell } -} -typealias ProposerTableCell = StackInfoTableCell -extension ProposerTableCell { - struct Model { - let title: String - let model: StackCellViewModel? + private func createBalanceCell( + with title: String, + viewModel: BalanceViewModelProtocol + ) -> StackTitleMultiValueCell { + let cell = StackTitleMultiValueCell() + cell.canSelect = false + cell.titleLabel.text = title + cell.rowContentView.valueView.bind(topValue: viewModel.amount, bottomValue: viewModel.price) + cell.rowContentView.titleView.hidesIcon = true + return cell } -} -typealias AmountSpendDetailsTableView = StackTableView -extension AmountSpendDetailsTableView { - struct Model { - let beneficiary: BeneficiaryModel - let requestedAmount: RequestedAmountModel + private func createTitleValueCell(with title: String, value: String) -> StackTableCell { + let cell = StackTableCell() + cell.titleLabel.text = title + cell.bind(details: value) + return cell } - struct BeneficiaryModel { - let title: String - let model: StackCellViewModel? + private func createInfoCell(with title: String, value: String) -> StackInfoTableCell { + let cell = StackInfoTableCell() + cell.titleLabel.text = title + cell.bind(details: value) + return cell } - struct RequestedAmountModel { - let title: String - let model: MultiValueView.Model + private func updateLayout() { + let views: [UIView?] = [proposerTableView, beneficiaryTableView, curveAndHashTableView] + views.forEach { + if let view = $0 { + containerView.stackView.setCustomSpacing(8.0, after: view) + } + } + + if let optView = views.reversed().first(where: { $0 != nil }), let lastView = optView { + containerView.stackView.setCustomSpacing(24.0, after: lastView) + } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift index 7df05ebb18..96b9d448a8 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift @@ -20,9 +20,9 @@ extension ReferendumStateLocal { var callHash: String? { switch proposal { case let .lookup(lookup): - return String(data: lookup.hash, encoding: .utf8) + return lookup.hash.toHex(includePrefix: true) case let .legacy(hash): - return String(data: hash, encoding: .utf8) + return hash.toHex(includePrefix: true) case .inline, .unknown, .none: return nil } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ViewModel/ReferendumFullDetailsViewModel.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ViewModel/ReferendumFullDetailsViewModel.swift new file mode 100644 index 0000000000..1612374ada --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ViewModel/ReferendumFullDetailsViewModel.swift @@ -0,0 +1,19 @@ +import Foundation + +enum ReferendumFullDetailsViewModel { + struct Proposer { + let proposer: DisplayAddressViewModel + let deposit: BalanceViewModelProtocol? + } + + struct Beneficiary { + let account: DisplayAddressViewModel + let amount: BalanceViewModelProtocol? + } + + struct CurveAndHash { + let approveCurve: String + let supportCurve: String + let callHash: String? + } +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift index 789f09ad08..0351a9bcfe 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift @@ -246,26 +246,26 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory ) models = [approved] - case let .rejected(atBlock): + case let .rejected(model): createdAt = nil let rejected = createVotedTerminal( status: R.string.localizable.governanceReferendumsStatusRejected(preferredLanguages: locale.rLanguages), - atBlock: atBlock, + atBlock: model.atBlock, currentBlock: currentBlock, blockTime: blockDuration, locale: locale ) models = [rejected] - case let .cancelled(atBlock): + case let .cancelled(model): createdAt = nil let cancelled = createVotedTerminal( status: R.string.localizable.governanceReferendumsStatusCancelled( preferredLanguages: locale.rLanguages ), - atBlock: atBlock, + atBlock: model.atBlock, currentBlock: currentBlock, blockTime: blockDuration, locale: locale @@ -284,12 +284,12 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory ) models = [killed] - case let .timedOut(atBlock): + case let .timedOut(model): createdAt = nil let timedOut = createVotedTerminal( status: R.string.localizable.governanceReferendumsStatusTimedOut(preferredLanguages: locale.rLanguages), - atBlock: atBlock, + atBlock: model.atBlock, currentBlock: currentBlock, blockTime: blockDuration, locale: locale diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 07c3416c0d..dea7f9017a 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1057,4 +1057,12 @@ "common.read.more" = "Read more"; "gov.referendum.title.fallback" = "Referendum %@"; "gov.referendum.description.fallback" = "Only the proposer can edit this description and the title. If you own proposer's account, visit Polkassembly and fill in information about your proposal"; -"common.full.details" = "Full details"; +"gov.full.details" = "Full details"; +"gov.proposer" = "Proposer"; +"gov.deposit" = "Deposit"; +"gov.beneficiary" = "Beneficiary"; +"gov.requested.amount" = "Requested amount"; +"gov.approve.curve" = "Approve Curve"; +"gov.support.curve" = "Support Curve"; +"gov.call.hash" = "Call Hash"; +"gov.parameters.json" = "Parameters JSON"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 8f99ed2cd2..9fec1c0ee4 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1058,4 +1058,12 @@ "common.read.more" = "Читать дальше"; "gov.referendum.title.fallback" = "Референдум %@"; "gov.referendum.description.fallback" = "Только создатель референдума может редактировать заголовок и описание. Если Вы владеете аккаунтом создателя референдума, то заполните информацию о референдуме на Polkassembly"; -"common.full.details" = "Техническая информация"; +"gov.full.details" = "Техническая информация"; +"gov.proposer" = "Создатель"; +"gov.deposit" = "Депозит"; +"gov.beneficiary" = "Получатель"; +"gov.requested.amount" = "Запрашиваемая сумма"; +"gov.approve.curve" = "Кривая подтверждения"; +"gov.support.curve" = "Кривая поддержки"; +"gov.call.hash" = "Хэш вызова"; +"gov.parameters.json" = "Параметры вызова"; From 5ccccd2b27cfbb786c9925fc46f3b89debba5308 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 27 Oct 2022 23:51:09 +0500 Subject: [PATCH 105/229] add copy action --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../Foundation/String+Substrate.swift | 14 +++++ .../Common/Protocols/CopyPresentable.swift | 55 +++++++++++++++++++ .../ReferendumFullDetailsPresenter.swift | 40 +++++++++++++- .../ReferendumFullDetailsProtocols.swift | 2 +- .../ReferendumFullDetailsViewLayout.swift | 4 ++ novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 8 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 novawallet/Common/Protocols/CopyPresentable.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index b05f8031c1..631cdecaf6 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1600,6 +1600,7 @@ 84A6171B2625AC3E007B75E1 /* CallCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A6171A2625AC3E007B75E1 /* CallCodingPath.swift */; }; 84A617262625AF51007B75E1 /* RuntimeMetadata+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A617252625AF51007B75E1 /* RuntimeMetadata+Internal.swift */; }; 84A6AB5E290AA7DF001B57B2 /* ReferendumFullDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A6AB5D290AA7DF001B57B2 /* ReferendumFullDetailsViewModel.swift */; }; + 84A6AB64290B021E001B57B2 /* CopyPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A6AB63290B021E001B57B2 /* CopyPresentable.swift */; }; 84A8FD8E265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A8FD8D265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift */; }; 84A90489288EA0E500DFC8E2 /* NoKeysCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A90488288EA0E500DFC8E2 /* NoKeysCommand.swift */; }; 84AA004326C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AA004226C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift */; }; @@ -4530,6 +4531,7 @@ 84A6171A2625AC3E007B75E1 /* CallCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallCodingPath.swift; sourceTree = ""; }; 84A617252625AF51007B75E1 /* RuntimeMetadata+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuntimeMetadata+Internal.swift"; sourceTree = ""; }; 84A6AB5D290AA7DF001B57B2 /* ReferendumFullDetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsViewModel.swift; sourceTree = ""; }; + 84A6AB63290B021E001B57B2 /* CopyPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyPresentable.swift; sourceTree = ""; }; 84A8FD8D265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmData.swift; sourceTree = ""; }; 84A90488288EA0E500DFC8E2 /* NoKeysCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoKeysCommand.swift; sourceTree = ""; }; 84AA004226C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeSyncServiceTests.swift; sourceTree = ""; }; @@ -9328,6 +9330,7 @@ 846A835528B8A5C700D92892 /* WalletCreationFlowCompleting.swift */, 846A835928B8C5EC00D92892 /* TransactionExpiredPresentable.swift */, 843074F828BF6201009D463B /* NoAccountSupportPresentable.swift */, + 84A6AB63290B021E001B57B2 /* CopyPresentable.swift */, ); path = Protocols; sourceTree = ""; @@ -15267,6 +15270,7 @@ 8479607E283B60AA0084E779 /* ActionLoadingView.swift in Sources */, 84466B3A28B7653E00FA1E0D /* LedgerPerformOperationProtocols.swift in Sources */, 8430AB1726023D2D005B1066 /* BaseStashNextState.swift in Sources */, + 84A6AB64290B021E001B57B2 /* CopyPresentable.swift in Sources */, 841AAC2126F6860B00F0A25E /* AssetBalanceFormatterFactory.swift in Sources */, 8418167528251BBC0007684A /* StorageListSyncResult.swift in Sources */, 88D997B028ABC8C0006135A5 /* BlurredTableViewCell.swift in Sources */, diff --git a/novawallet/Common/Extension/Foundation/String+Substrate.swift b/novawallet/Common/Extension/Foundation/String+Substrate.swift index 55d7da07f8..a692efa286 100644 --- a/novawallet/Common/Extension/Foundation/String+Substrate.swift +++ b/novawallet/Common/Extension/Foundation/String+Substrate.swift @@ -28,6 +28,20 @@ extension String { return replacedCamelCase } + func twoLineString(with threshold: Int) -> String { + guard count > threshold else { + return self + } + + let leftPartCount = count / 2 + + guard leftPartCount > 0 else { + return self + } + + return prefix(leftPartCount) + "\n" + suffix(count - leftPartCount) + } + var twoLineAddress: String { let leftPartCount = count / 2 diff --git a/novawallet/Common/Protocols/CopyPresentable.swift b/novawallet/Common/Protocols/CopyPresentable.swift new file mode 100644 index 0000000000..07a81bb2d5 --- /dev/null +++ b/novawallet/Common/Protocols/CopyPresentable.swift @@ -0,0 +1,55 @@ +import Foundation +import SoraFoundation + +protocol CopyPresentable { + func presentCopy( + from view: ControllerBackedProtocol, + value: String, + locale: Locale + ) +} + +extension CopyPresentable where Self: AlertPresentable { + private func copyAddress( + from view: ControllerBackedProtocol, + value: String, + locale: Locale + ) { + UIPasteboard.general.string = value + + let title = R.string.localizable.commonCopied(preferredLanguages: locale.rLanguages) + let controller = ModalAlertFactory.createSuccessAlert(title) + + view.controller.present( + controller, + animated: true, + completion: nil + ) + } + + func presentCopy( + from view: ControllerBackedProtocol, + value: String, + locale: Locale + ) { + let copyTitle = R.string.localizable.commonCopy(preferredLanguages: locale.rLanguages) + + let title = value.twoLineString(with: 16) + + let action = AlertPresentableAction( + title: copyTitle, + style: .normal + ) { [weak self] in + self?.copyAddress(from: view, value: value, locale: locale) + } + + let viewModel = AlertPresentableViewModel( + title: title, + message: nil, + actions: [action], + closeAction: nil + ) + + present(viewModel: viewModel, style: .actionSheet, from: view) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index a6b39fa146..0fc1ab6584 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -120,6 +120,19 @@ final class ReferendumFullDetailsPresenter { provideBeneficiaryViewModel() provideCurveAndHashViewModel() } + + private func presentDetails(for address: AccountAddress) { + guard let view = view else { + return + } + + wireframe.presentAccountOptions( + from: view, + address: address, + chain: chain, + locale: selectedLocale + ) + } } extension ReferendumFullDetailsPresenter: ReferendumFullDetailsPresenterProtocol { @@ -128,11 +141,32 @@ extension ReferendumFullDetailsPresenter: ReferendumFullDetailsPresenterProtocol updateView() } - func presentProposer() {} + func presentProposer() { + guard let address = try? referendum.proposer?.toAddress(using: chain.chainFormat) else { + return + } - func presentBeneficiary() {} + presentDetails(for: address) + } - func presentCallHash() {} + func presentBeneficiary() { + guard + let address = try? actionDetails.amountSpendDetails?.beneficiary.accountId?.toAddress( + using: chain.chainFormat + ) else { + return + } + + presentDetails(for: address) + } + + func presentCallHash() { + guard let view = view, let callHash = referendum.state.callHash else { + return + } + + wireframe.presentCopy(from: view, value: callHash, locale: selectedLocale) + } } extension ReferendumFullDetailsPresenter: ReferendumFullDetailsInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift index d0e7b2f00f..c5890e14f0 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift @@ -25,7 +25,7 @@ protocol ReferendumFullDetailsInteractorOutputProtocol: AnyObject { } protocol ReferendumFullDetailsWireframeProtocol: ErrorPresentable, AlertPresentable, AddressOptionsPresentable, - CommonRetryable {} + CommonRetryable, CopyPresentable {} enum ReferendumFullDetailsError: Error { case priceFailed(Error) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index 8fc8234fd4..8ab4b59e9a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -53,6 +53,8 @@ final class ReferendumFullDetailsViewLayout: UIView { viewModel: viewModel.proposer ) + self.proposerCell = proposerCell + proposerTableView?.addArrangedSubview(proposerCell) if let deposit = viewModel.deposit { @@ -86,6 +88,8 @@ final class ReferendumFullDetailsViewLayout: UIView { viewModel: viewModel.account ) + self.beneficiaryCell = beneficiaryCell + beneficiaryTableView?.addArrangedSubview(beneficiaryCell) if let amount = viewModel.amount { diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index dea7f9017a..7ff46a2d76 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1066,3 +1066,4 @@ "gov.support.curve" = "Support Curve"; "gov.call.hash" = "Call Hash"; "gov.parameters.json" = "Parameters JSON"; +"common.copy" = "Copy";" diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 9fec1c0ee4..3b4d710027 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1067,3 +1067,4 @@ "gov.support.curve" = "Кривая поддержки"; "gov.call.hash" = "Хэш вызова"; "gov.parameters.json" = "Параметры вызова"; +"common.copy" = "Копировать"; From fb433c8d7d0a713f0b278cf6f80e433aae8fb171 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 00:29:30 +0500 Subject: [PATCH 106/229] support too long json --- .../Model/ReferendumActionLocal.swift | 16 +++++++++- .../Gov2ActionOperationFactory.swift | 23 +++++++------- .../ReferendumFullDetailsInteractor.swift | 11 ++++--- .../ReferendumFullDetailsPresenter.swift | 19 ++++++++++-- .../ReferendumFullDetailsProtocols.swift | 3 +- .../ReferendumFullDetailsViewController.swift | 4 +++ .../ReferendumFullDetailsViewLayout.swift | 30 +++++++++++++++++++ novawallet/en.lproj/Localizable.strings | 3 +- novawallet/ru.lproj/Localizable.strings | 1 + 9 files changed, 90 insertions(+), 20 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift index e6bf4cccee..8574ba9f20 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumActionLocal.swift @@ -8,6 +8,20 @@ struct ReferendumActionLocal { let beneficiary: MultiAddress } + enum Call { + case concrete(C) + case tooLong + + var value: C? { + switch self { + case let .concrete(call): + return call + case .tooLong: + return nil + } + } + } + let amountSpendDetails: AmountSpendDetails? - let call: RuntimeCall? + let call: Call>? } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift index 8424d238ff..02affaad19 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift @@ -13,13 +13,14 @@ final class Gov2ActionOperationFactory { self.operationQueue = operationQueue } + // switftlint:disable:next function_body_length private func createCallFetchWrapper( dependingOn codingFactoryOperation: BaseOperation, referendum: ReferendumLocal, requestFactory: StorageRequestFactoryProtocol, connection: JSONRPCEngine - ) -> CompoundOperationWrapper?> { - let callFetchClosure: (Data) -> CompoundOperationWrapper?> = { hash in + ) -> CompoundOperationWrapper>?> { + let callFetchClosure: (Data) -> CompoundOperationWrapper>?> = { hash in let statusKeyParams: () throws -> [BytesCodable] = { [BytesCodable(wrappedValue: hash)] } @@ -51,7 +52,7 @@ final class Gov2ActionOperationFactory { callFetchWrapper.addDependency(wrapper: statusFetchWrapper) - let mappingOperation = ClosureOperation?> { + let mappingOperation = ClosureOperation>?> { let callKeys = try callKeyParams() guard !callKeys.isEmpty else { @@ -67,10 +68,12 @@ final class Gov2ActionOperationFactory { let decoder = try codingFactory.createDecoder(from: response.wrappedValue) - return try decoder.read( + let call: RuntimeCall = try decoder.read( of: GenericType.call.name, with: codingFactory.createRuntimeJsonContext().toRawContext() ) + + return .concrete(call) } mappingOperation.addDependency(callFetchWrapper.targetOperation) @@ -80,7 +83,7 @@ final class Gov2ActionOperationFactory { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) } - let callDecodingService = OperationCombiningService?>( + let callDecodingService = OperationCombiningService>?>( operationManager: OperationManager(operationQueue: operationQueue) ) { switch referendum.state.proposal { @@ -88,13 +91,13 @@ final class Gov2ActionOperationFactory { let wrapper = callFetchClosure(hash) return [wrapper] case let .inline(value): - return [CompoundOperationWrapper.createWithResult(value)] + return [CompoundOperationWrapper.createWithResult(.concrete(value))] case let .lookup(lookup): if lookup.len <= Self.maxFetchCallSize { let wrapper = callFetchClosure(lookup.hash) return [wrapper] } else { - return [] + return [CompoundOperationWrapper.createWithResult(.tooLong)] } case .none, .unknown: return [] @@ -102,7 +105,7 @@ final class Gov2ActionOperationFactory { } let callDecodingOperation = callDecodingService.longrunOperation() - let mappingOperation = ClosureOperation?> { + let mappingOperation = ClosureOperation>?> { try callDecodingOperation.extractNoCancellableResultData().first ?? nil } @@ -112,7 +115,7 @@ final class Gov2ActionOperationFactory { } private func createSpendAmountExtractionWrapper( - dependingOn callOperation: BaseOperation?>, + dependingOn callOperation: BaseOperation>?>, codingFactoryOperation: BaseOperation, connection: JSONRPCEngine, requestFactory: StorageRequestFactoryProtocol @@ -121,7 +124,7 @@ final class Gov2ActionOperationFactory { let fetchService = OperationCombiningService( operationManager: operationManager ) { - guard let call = try callOperation.extractNoCancellableResultData() else { + guard let call = try callOperation.extractNoCancellableResultData()?.value else { return [CompoundOperationWrapper.createWithResult(nil)] } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift index 47540e81de..6beeb459c5 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift @@ -40,20 +40,23 @@ final class ReferendumFullDetailsInteractor { } private func formatJSON() { - guard let call = referendumAction.call else { - presenter?.didReceive(json: nil) + guard let wrappedCall = referendumAction.call else { + presenter?.didReceive(call: nil) return } do { - let json = try call.toScaleCompatibleJSON() + guard let json = try wrappedCall.value?.toScaleCompatibleJSON() else { + presenter?.didReceive(call: .tooLong) + return + } let processingOperation = processingOperationFactory.createProcessingOperation(for: json) processingOperation.completionBlock = { [weak self] in DispatchQueue.main.async { do { let result = try processingOperation.extractNoCancellableResultData() - self?.presenter?.didReceive(json: result) + self?.presenter?.didReceive(call: .concrete(result)) } catch { self?.presenter?.didReceive(error: .processingJSON(error)) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index 0fc1ab6584..4a2d40f6e8 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -17,7 +17,7 @@ final class ReferendumFullDetailsPresenter { let identities: [AccountAddress: AccountIdentity] private var price: PriceData? - private var json: String? + private var call: ReferendumActionLocal.Call? init( interactor: ReferendumFullDetailsInteractorInputProtocol, @@ -115,10 +115,22 @@ final class ReferendumFullDetailsPresenter { view?.didReceive(params: model) } + private func provideJson() { + switch call { + case let .concrete(json): + view?.didReceive(json: json) + case .tooLong: + view?.didReceiveTooLongJson() + case .none: + view?.didReceive(json: nil) + } + } + private func updateView() { provideProposerViewModel() provideBeneficiaryViewModel() provideCurveAndHashViewModel() + provideJson() } private func presentDetails(for address: AccountAddress) { @@ -177,8 +189,9 @@ extension ReferendumFullDetailsPresenter: ReferendumFullDetailsInteractorOutputP provideBeneficiaryViewModel() } - func didReceive(json: String?) { - view?.didReceive(json: json) + func didReceive(call: ReferendumActionLocal.Call?) { + self.call = call + provideJson() } func didReceive(error: ReferendumFullDetailsError) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift index c5890e14f0..55261f7268 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift @@ -3,6 +3,7 @@ protocol ReferendumFullDetailsViewProtocol: ControllerBackedProtocol { func didReceive(beneficiary: ReferendumFullDetailsViewModel.Beneficiary?) func didReceive(params: ReferendumFullDetailsViewModel.CurveAndHash?) func didReceive(json: String?) + func didReceiveTooLongJson() } protocol ReferendumFullDetailsPresenterProtocol: AnyObject { @@ -20,7 +21,7 @@ protocol ReferendumFullDetailsInteractorInputProtocol: AnyObject { protocol ReferendumFullDetailsInteractorOutputProtocol: AnyObject { func didReceive(price: PriceData?) - func didReceive(json: String?) + func didReceive(call: ReferendumActionLocal.Call?) func didReceive(error: ReferendumFullDetailsError) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift index 19a05da6db..702e07165f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift @@ -81,6 +81,10 @@ extension ReferendumFullDetailsViewController: ReferendumFullDetailsViewProtocol func didReceive(json: String?) { rootView.setJson(viewModel: json, locale: selectedLocale) } + + func didReceiveTooLongJson() { + rootView.setTooLongJson(for: selectedLocale) + } } extension ReferendumFullDetailsViewController: Localizable { diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index 8ab4b59e9a..0888cb7b4f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -1,4 +1,5 @@ import UIKit +import SoraUI final class ReferendumFullDetailsViewLayout: UIView { let containerView: ScrollableContainerView = { @@ -183,6 +184,35 @@ final class ReferendumFullDetailsViewLayout: UIView { } } + func setTooLongJson(for locale: Locale) { + jsonView?.removeFromSuperview() + + let jsonView: GenericMultiValueView = .create { + $0.valueTop.apply(style: .caption1White64) + $0.valueTop.textAlignment = .left + $0.spacing = 12.0 + + let emptyStateView = $0.valueBottom + emptyStateView.image = R.image.iconEmptySearch() + emptyStateView.titleFont = .regularFootnote + emptyStateView.titleColor = R.color.colorWhite64()! + emptyStateView.verticalSpacing = 0.0 + } + + jsonView.valueTop.text = R.string.localizable.govParametersJson(preferredLanguages: locale.rLanguages) + + jsonView.valueBottom.title = R.string.localizable.commonTooLongPreview( + preferredLanguages: locale.rLanguages + ) + + containerView.stackView.addArrangedSubview(jsonView) + jsonView.snp.makeConstraints { + $0.height.equalTo(150) + } + + self.jsonView = jsonView + } + private func insertView(_ view: UIView, afterOneOf subviews: [UIView?]) { if let optSubview = subviews.first(where: { $0 != nil }), let subview = optSubview { containerView.stackView.insertArranged(view: view, after: subview) diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 7ff46a2d76..d597942794 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1066,4 +1066,5 @@ "gov.support.curve" = "Support Curve"; "gov.call.hash" = "Call Hash"; "gov.parameters.json" = "Parameters JSON"; -"common.copy" = "Copy";" +"common.copy" = "Copy"; +"common.too.long.preview" = "Too long for preview"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 3b4d710027..7da64b3fd7 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1068,3 +1068,4 @@ "gov.call.hash" = "Хэш вызова"; "gov.parameters.json" = "Параметры вызова"; "common.copy" = "Копировать"; +"common.too.long.preview" = "Слишком большой размер для просмотра"; From cf1ed28c2917e99451aa6e33d42cb3b752156ad8 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 00:51:21 +0500 Subject: [PATCH 107/229] too long preview --- .../Common/Protocols/CopyPresentable.swift | 2 +- .../ReferendumFullDetailsViewLayout.swift | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/novawallet/Common/Protocols/CopyPresentable.swift b/novawallet/Common/Protocols/CopyPresentable.swift index 07a81bb2d5..838f694a04 100644 --- a/novawallet/Common/Protocols/CopyPresentable.swift +++ b/novawallet/Common/Protocols/CopyPresentable.swift @@ -47,7 +47,7 @@ extension CopyPresentable where Self: AlertPresentable { title: title, message: nil, actions: [action], - closeAction: nil + closeAction: R.string.localizable.commonCancel(preferredLanguages: locale.rLanguages) ) present(viewModel: viewModel, style: .actionSheet, from: view) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index 0888cb7b4f..62bdd42d30 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -187,28 +187,29 @@ final class ReferendumFullDetailsViewLayout: UIView { func setTooLongJson(for locale: Locale) { jsonView?.removeFromSuperview() - let jsonView: GenericMultiValueView = .create { + let jsonView: GenericMultiValueView> = .create { $0.valueTop.apply(style: .caption1White64) $0.valueTop.textAlignment = .left $0.spacing = 12.0 - let emptyStateView = $0.valueBottom - emptyStateView.image = R.image.iconEmptySearch() + let emptyStateView = $0.valueBottom.view + emptyStateView.layoutType = .verticalImageFirst + emptyStateView.iconImage = R.image.iconEmptySearch()! emptyStateView.titleFont = .regularFootnote emptyStateView.titleColor = R.color.colorWhite64()! - emptyStateView.verticalSpacing = 0.0 + emptyStateView.spacingBetweenLabelAndIcon = 0 + + $0.valueBottom.contentInsets = .zero + $0.valueBottom.innerInsets = UIEdgeInsets(top: 12, left: 12, bottom: 24, right: 12) } jsonView.valueTop.text = R.string.localizable.govParametersJson(preferredLanguages: locale.rLanguages) - jsonView.valueBottom.title = R.string.localizable.commonTooLongPreview( + jsonView.valueBottom.view.title = R.string.localizable.commonTooLongPreview( preferredLanguages: locale.rLanguages ) containerView.stackView.addArrangedSubview(jsonView) - jsonView.snp.makeConstraints { - $0.height.equalTo(150) - } self.jsonView = jsonView } From 49350581cd05bcd83d38f29faf89c3123af5c760 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 09:24:34 +0500 Subject: [PATCH 108/229] localize names --- .../ReferendumFullDetailsPresenter.swift | 4 ++-- .../ReferendumStateLocal+Presenter.swift | 13 +++++++------ novawallet/en.lproj/Localizable.strings | 4 ++++ novawallet/ru.lproj/Localizable.strings | 4 ++++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index 4a2d40f6e8..5ebae00571 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -107,8 +107,8 @@ final class ReferendumFullDetailsPresenter { let callHash = referendum.state.callHash let model = ReferendumFullDetailsViewModel.CurveAndHash( - approveCurve: approvalCurve.displayName, - supportCurve: supportCurve.displayName, + approveCurve: approvalCurve.displayName(for: selectedLocale), + supportCurve: supportCurve.displayName(for: selectedLocale), callHash: callHash ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift index 96b9d448a8..6398b09bd7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift @@ -1,3 +1,5 @@ +import Foundation + extension ReferendumStateLocal { var approvalCurve: Referenda.Curve? { switch voting { @@ -46,17 +48,16 @@ extension ReferendumStateLocal { } extension Referenda.Curve { - // TODO: localize? - var displayName: String { + func displayName(for locale: Locale) -> String { switch self { case .linearDecreasing: - return "Linear Decreasing" + return R.string.localizable.govLinearDecreasing(preferredLanguages: locale.rLanguages) case .reciprocal: - return "Reciprocal" + return R.string.localizable.govReciprocal(preferredLanguages: locale.rLanguages) case .steppedDecreasing: - return "Stepped Decreasing" + return R.string.localizable.govSteppedDecreasing(preferredLanguages: locale.rLanguages) case .unknown: - return "Unknown" + return R.string.localizable.govUnknown(preferredLanguages: locale.rLanguages) } } } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index d597942794..ce6e9bc5f9 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1068,3 +1068,7 @@ "gov.parameters.json" = "Parameters JSON"; "common.copy" = "Copy"; "common.too.long.preview" = "Too long for preview"; +"gov.linear.decreasing" = "Linear Decreasing"; +"gov.stepped.decreasing" = "Stepped Decreasing"; +"gov.reciprocal" = "Reciprocal"; +"gov.unknown" = "Unknown"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 7da64b3fd7..66184f6d03 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1069,3 +1069,7 @@ "gov.parameters.json" = "Параметры вызова"; "common.copy" = "Копировать"; "common.too.long.preview" = "Слишком большой размер для просмотра"; +"gov.linear.decreasing" = "Линейное убывание"; +"gov.stepped.decreasing" = "Ступенчатое убывание"; +"gov.reciprocal" = "Обратное линейное убывание"; +"gov.unknown" = "Неизвестно"; From f896ab85bdc149a11ecb5245c5fafee6a44985c2 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 11:07:12 +0500 Subject: [PATCH 109/229] fix locked amount and period --- .../Model/ReferendumVotingLocal.swift | 20 +++ .../Operation/Gov2LockStateFactory.swift | 142 ++++++++++++------ .../Operation/Gov2OperationFactory.swift | 3 +- .../GovernanceOperationProtocols.swift | 2 +- .../ReferendumVoteInteractor.swift | 4 +- .../ReferendumVoteProtocols.swift | 2 +- .../ReferendumVoteConfirmPresenter.swift | 6 +- .../ReferendumVoteSetupPresenter.swift | 6 +- 8 files changed, 134 insertions(+), 51 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift index 66d658525b..1d07d5e3ba 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift @@ -4,6 +4,7 @@ struct ReferendumAccountVotingDistribution { let votes: [ReferendumIdLocal: ReferendumAccountVoteLocal] let votedTracks: [TrackIdLocal: Set] let delegatings: [TrackIdLocal: ReferendumDelegatingLocal] + let priorLocks: [TrackIdLocal: ConvictionVoting.PriorLock] let maxVotesPerTrack: UInt32 func addingVote( @@ -17,6 +18,7 @@ struct ReferendumAccountVotingDistribution { votes: newVotes, votedTracks: votedTracks, delegatings: delegatings, + priorLocks: priorLocks, maxVotesPerTrack: maxVotesPerTrack ) } @@ -32,6 +34,7 @@ struct ReferendumAccountVotingDistribution { votes: votes, votedTracks: votedTracks, delegatings: newDelegatings, + priorLocks: priorLocks, maxVotesPerTrack: maxVotesPerTrack ) } @@ -49,6 +52,23 @@ struct ReferendumAccountVotingDistribution { votes: votes, votedTracks: newVotedTracks, delegatings: delegatings, + priorLocks: priorLocks, + maxVotesPerTrack: maxVotesPerTrack + ) + } + + func addingPriorLock( + _ priorLock: ConvictionVoting.PriorLock, + track: TrackIdLocal + ) -> ReferendumAccountVotingDistribution { + var newPriorLocks = priorLocks + newPriorLocks[track] = priorLock + + return ReferendumAccountVotingDistribution( + votes: votes, + votedTracks: votedTracks, + delegatings: delegatings, + priorLocks: newPriorLocks, maxVotesPerTrack: maxVotesPerTrack ) } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift index 1be05129d1..66b643d21c 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift @@ -3,6 +3,22 @@ import RobinHood import SubstrateSdk import BigInt +/** + * Class that calculates: + * Locked amount diff - maximum amount of tokens locked before vote is applied and after + * Locked period diff - period of time needed to unlock all the tokens before vote is applied and after. + * + * Locked amount calculation assumes that no unlocks can happen during voting (event if voting for the same referendum). + * So the diff may not decrease. + * + * Locked period is calculated first by maximizing estimation for unlock block of votes (only nonzero amount). + * And then maximizing result between maximum period for votes and prior locks + * (taking into account both casting votes and delegations). + * + * Note that locked period calculation uses an estimation that takes maximum time when voting for particular referendum + * may end. + */ + final class Gov2LockStateFactory { struct AdditionalInfo { let tracks: [Referenda.TrackId: Referenda.TrackInfo] @@ -102,7 +118,7 @@ final class Gov2LockStateFactory { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: fetchOperations) } - private func calculateLocking( + private func estimateVoteLockingPeriod( for referendumInfo: ReferendumInfo, accountVote: ReferendumAccountVoteLocal, additionalInfo: AdditionalInfo @@ -142,8 +158,55 @@ final class Gov2LockStateFactory { } } + private func calculatePriorLockMax(from trackVotes: ReferendumTracksVotingDistribution) -> BlockNumber? { + let optCastingMax = trackVotes.votes.priorLocks.values + .filter { $0.amount > 0 } + .map(\.unlockAt) + .max() + + let optDelegatingMax = trackVotes.votes.delegatings.values + .compactMap { $0.prior.amount > 0 ? $0.prior.unlockAt : nil } + .max() + + if let castingMax = optCastingMax, let delegatingMax = optDelegatingMax { + return max(castingMax, delegatingMax) + } else if let castingMax = optCastingMax { + return castingMax + } else { + return optDelegatingMax + } + } + + private func calculateMaxLock( + for referendums: [ReferendumIdLocal: ReferendumInfo], + trackVotes: ReferendumTracksVotingDistribution, + additions: AdditionalInfo + ) -> BlockNumber? { + let optVotesMax: Moment? = referendums.compactMap { referendumKeyValue in + let referendumIndex = referendumKeyValue.key + let referendum = referendumKeyValue.value + + let accountVoting = trackVotes.votes + guard let vote = accountVoting.votes[referendumIndex], vote.totalBalance > 0 else { + return nil + } + + return estimateVoteLockingPeriod(for: referendum, accountVote: vote, additionalInfo: additions) + }.max() + + let optPriorMax = calculatePriorLockMax(from: trackVotes) + + if let votesMax = optVotesMax, let priorMax = optPriorMax { + return max(votesMax, priorMax) + } else if let votesMax = optVotesMax { + return votesMax + } else { + return optPriorMax + } + } + private func createStateDiffOperation( - for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + for trackVotes: ReferendumTracksVotingDistribution, newVote: ReferendumNewVote?, referendumsOperation: BaseOperation<[ReferendumIdLocal: ReferendumInfo]>, additionalInfoOperation: BaseOperation @@ -152,49 +215,43 @@ final class Gov2LockStateFactory { let referendums = try referendumsOperation.extractNoCancellableResultData() let additions = try additionalInfoOperation.extractNoCancellableResultData() - let oldAmount = votes.values.map(\.totalBalance).max() ?? 0 - - let oldPeriod: Moment? = referendums.compactMap { referendumKeyValue in - let referendumIndex = referendumKeyValue.key - let referendum = referendumKeyValue.value - - guard let vote = votes[referendumIndex], vote.totalBalance > 0 else { - return nil - } + let oldAmount = trackVotes.trackLocks.map(\.amount).max() ?? 0 - return self.calculateLocking(for: referendum, accountVote: vote, additionalInfo: additions) - }.max() + let oldPeriod: Moment? = self.calculateMaxLock( + for: referendums, + trackVotes: trackVotes, + additions: additions + ) let oldState = GovernanceLockState(maxLockedAmount: oldAmount, lockedUntil: oldPeriod) let newState: GovernanceLockState? - if let newVote = newVote { - let filteredVotes = votes.filter { $0.key != newVote.index } - let newAmount = (filteredVotes.values.map(\.totalBalance) + [newVote.voteAction.amount]).max() ?? 0 - - let newPeriod: Moment? = referendums.compactMap { referendumKeyValue in - let referendumIndex = referendumKeyValue.key - let referendum = referendumKeyValue.value - - let accountVote: ReferendumAccountVoteLocal - - if referendumIndex == newVote.index { - guard newVote.voteAction.amount > 0 else { - return nil - } - - accountVote = newVote.toAccountVote() - } else { - guard let vote = filteredVotes[referendumIndex], vote.totalBalance > 0 else { - return nil - } - - accountVote = vote - } - - return self.calculateLocking(for: referendum, accountVote: accountVote, additionalInfo: additions) - }.max() + if let newVote = newVote, newVote.voteAction.amount > 0 { + let newAmount = max(oldAmount, newVote.voteAction.amount) + + // as we replacing the vote we can immediately claim previos one so don't take into account + let filteredReferendums = referendums.filter { $0.key != newVote.index } + + let periodWithoutReferendum = self.calculateMaxLock( + for: filteredReferendums, + trackVotes: trackVotes, + additions: additions + ) + + let newPeriod: Moment? + + if + let referendum = referendums[newVote.index], + let periodWithNewVote = self.estimateVoteLockingPeriod( + for: referendum, + accountVote: newVote.toAccountVote(), + additionalInfo: additions + ) { + newPeriod = periodWithoutReferendum.flatMap { max(periodWithNewVote, $0) } ?? periodWithNewVote + } else { + newPeriod = periodWithoutReferendum + } newState = GovernanceLockState(maxLockedAmount: newAmount, lockedUntil: newPeriod) } else { @@ -208,7 +265,7 @@ final class Gov2LockStateFactory { extension Gov2LockStateFactory: GovernanceLockStateFactoryProtocol { func calculateLockStateDiff( - for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + for trackVotes: ReferendumTracksVotingDistribution, newVote: ReferendumNewVote?, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, @@ -216,7 +273,8 @@ extension Gov2LockStateFactory: GovernanceLockStateFactoryProtocol { ) -> CompoundOperationWrapper { let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - var allReferendumIds = Set(votes.keys) + let accountVoting = trackVotes.votes + var allReferendumIds = Set(accountVoting.votes.keys) if let newVoteIndex = newVote?.index { allReferendumIds.insert(newVoteIndex) @@ -235,7 +293,7 @@ extension Gov2LockStateFactory: GovernanceLockStateFactoryProtocol { additionalInfoWrapper.addDependency(operations: [codingFactoryOperation]) let calculationOperation = createStateDiffOperation( - for: votes, + for: trackVotes, newVote: newVote, referendumsOperation: referendumsWrapper.targetOperation, additionalInfoOperation: additionalInfoWrapper.targetOperation diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 571c154c44..16b703b0cd 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -324,6 +324,7 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { votes: [:], votedTracks: [:], delegatings: [:], + priorLocks: [:], maxVotesPerTrack: maxVotes ) @@ -340,7 +341,7 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { } return newResult.addingVote(localVote, referendumId: ReferendumIdLocal(vote.pollIndex)) - } + }.addingPriorLock(castingVoting.prior, track: track) case let .delegating(delegatingVoting): let delegatingLocal = ReferendumDelegatingLocal(remote: delegatingVoting) return resultVoting.addingDelegating(delegatingLocal, trackId: track) diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift index d4be0dfe19..362e6cfb2f 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -32,7 +32,7 @@ protocol ReferendumActionOperationFactoryProtocol { protocol GovernanceLockStateFactoryProtocol { func calculateLockStateDiff( - for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + for trackVotes: ReferendumTracksVotingDistribution, newVote: ReferendumNewVote?, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift index d0022f6c6e..5d17390785 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift @@ -221,14 +221,14 @@ extension ReferendumVoteInteractor: ReferendumVoteInteractorInputProtocol { } func refreshLockDiff( - for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + for trackVoting: ReferendumTracksVotingDistribution, newVote: ReferendumNewVote?, blockHash: Data? ) { clear(cancellable: &lockDiffCancellable) let wrapper = lockStateFactory.calculateLockStateDiff( - for: votes, + for: trackVoting, newVote: newVote, from: connection, runtimeProvider: runtimeProvider, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift index e8f7feb396..131e86fbeb 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteProtocols.swift @@ -6,7 +6,7 @@ protocol ReferendumVoteInteractorInputProtocol: AnyObject { func remakeSubscriptions() func estimateFee(for vote: ReferendumVoteAction) func refreshLockDiff( - for votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + for trackVoting: ReferendumTracksVotingDistribution, newVote: ReferendumNewVote?, blockHash: Data? ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift index 8644592e5b..d63666c085 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift @@ -206,8 +206,12 @@ final class ReferendumVoteConfirmPresenter { } private func refreshLockDiff() { + guard let trackVoting = votesResult?.value else { + return + } + interactor.refreshLockDiff( - for: votesResult?.value?.votes.votes ?? [:], + for: trackVoting, newVote: vote, blockHash: votesResult?.blockHash ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 7b5cdd1e49..759bdac55e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -268,14 +268,14 @@ final class ReferendumVoteSetupPresenter { } private func refreshLockDiff() { - guard let votesResult = votesResult, let newVote = deriveNewVote() else { + guard let trackVoting = votesResult?.value, let newVote = deriveNewVote() else { return } interactor.refreshLockDiff( - for: votesResult.value?.votes.votes ?? [:], + for: trackVoting, newVote: newVote, - blockHash: votesResult.blockHash + blockHash: votesResult?.blockHash ) } From e7cbd7d4affaad922a7938c76b1579019fcb9adb Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 11:10:23 +0500 Subject: [PATCH 110/229] fix zero balance --- .../ReferendumVoteSetupPresenter.swift | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index 759bdac55e..d9fb5ff064 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -74,20 +74,20 @@ final class ReferendumVoteSetupPresenter { } private func updateAvailableBalanceView() { - if let assetBalance = assetBalance { - let precision = chain.utilityAsset()?.displayInfo.assetPrecision ?? 0 - let balanceDecimal = Decimal.fromSubstrateAmount( - assetBalance.freeInPlank, - precision: precision - ) ?? 0 - - let viewModel = balanceViewModelFactory.balanceFromPrice( - balanceDecimal, - priceData: nil - ).value(for: selectedLocale).amount - - view?.didReceiveBalance(viewModel: viewModel) - } + let freeInPlank = assetBalance?.freeInPlank ?? 0 + + let precision = chain.utilityAsset()?.displayInfo.assetPrecision ?? 0 + let balanceDecimal = Decimal.fromSubstrateAmount( + freeInPlank, + precision: precision + ) ?? 0 + + let viewModel = balanceViewModelFactory.balanceFromPrice( + balanceDecimal, + priceData: nil + ).value(for: selectedLocale).amount + + view?.didReceiveBalance(viewModel: viewModel) } private func updateChainAssetViewModel() { From 482e5a613b881d068829575ed861e83ef9f4f2d0 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 11:21:40 +0500 Subject: [PATCH 111/229] fix negative on confirm --- .../Vote/Governance/Operation/Gov2LockStateFactory.swift | 4 +++- .../ReferendumVoteConfirmPresenter.swift | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift index 66b643d21c..8f65b44054 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift @@ -227,7 +227,7 @@ final class Gov2LockStateFactory { let newState: GovernanceLockState? - if let newVote = newVote, newVote.voteAction.amount > 0 { + if let newVote = newVote { let newAmount = max(oldAmount, newVote.voteAction.amount) // as we replacing the vote we can immediately claim previos one so don't take into account @@ -241,7 +241,9 @@ final class Gov2LockStateFactory { let newPeriod: Moment? + // if amount is zero we don't take into account the vote for the referendum if + newVote.voteAction.amount > 0, let referendum = referendums[newVote.index], let periodWithNewVote = self.estimateVoteLockingPeriod( for: referendum, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift index d63666c085..cd857c6340 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift @@ -74,7 +74,7 @@ final class ReferendumVoteConfirmPresenter { return } - let viewModel = balanceViewModelFactory.spendingAmountFromPrice( + let viewModel = balanceViewModelFactory.balanceFromPrice( decimalAmount, priceData: priceData ).value(for: selectedLocale) From 44f3412c91278bd1b59ace4e799307ed744b0fb7 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 12:32:09 +0500 Subject: [PATCH 112/229] hide threshold view when reached --- .../Extension/Foundation/NumberFormatter.swift | 6 ++++++ .../ReferendumDetailsViewFactory.swift | 2 +- .../Vote/Governance/View/VotingProgressView.swift | 15 ++++++++++++--- .../ViewModel/ReferendumsModelFactory.swift | 6 ++++-- .../Vote/Parent/VoteChildPresenterFactory.swift | 2 +- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/novawallet/Common/Extension/Foundation/NumberFormatter.swift b/novawallet/Common/Extension/Foundation/NumberFormatter.swift index 7a4e8f80e0..f013207c90 100644 --- a/novawallet/Common/Extension/Foundation/NumberFormatter.swift +++ b/novawallet/Common/Extension/Foundation/NumberFormatter.swift @@ -77,6 +77,12 @@ extension NumberFormatter { return numberFormatter } + static var referendumPercent: NumberFormatter { + let numberFormatter = percentHalfEven + numberFormatter.minimumFractionDigits = 0 + return numberFormatter + } + static var index: NumberFormatter { let numberFormatter = quantity numberFormatter.positivePrefix = "#" diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 65f06e2dfc..6ea08dd978 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -35,7 +35,7 @@ struct ReferendumDetailsViewFactory { let referendumViewModelFactory = ReferendumsModelFactory( statusViewModelFactory: statusViewModelFactory, assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), - percentFormatter: NumberFormatter.percentHalfEven.localizableResource(), + percentFormatter: NumberFormatter.referendumPercent.localizableResource(), indexFormatter: indexFormatter ) diff --git a/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift index bb797a307e..f12b2210a4 100644 --- a/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift +++ b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift @@ -53,10 +53,15 @@ final class VotingProgressView: UIView { extension VotingProgressView: BindableView { struct Model { - let support: TitleIconViewModel? + let support: SupportModel? let approval: ApprovalModel } + struct SupportModel { + let titleIcon: TitleIconViewModel + let completed: Bool + } + struct ApprovalModel { let passThreshold: Decimal let ayeProgress: Decimal? @@ -75,8 +80,12 @@ extension VotingProgressView: BindableView { passProgressLabel.text = viewModel.approval.passMessage nayProgressLabel.text = viewModel.approval.nayMessage - thresholdView.bind(viewModel: viewModel.support) - thresholdView.isHidden = viewModel.support == nil + if let support = viewModel.support, !support.completed { + thresholdView.isHidden = false + thresholdView.bind(viewModel: support.titleIcon) + } else { + thresholdView.isHidden = true + } } } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 5a60c81107..134f7b253a 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -275,7 +275,7 @@ final class ReferendumsModelFactory { chain: ChainModel, currentBlock: BlockNumber, locale: Locale - ) -> TitleIconViewModel? { + ) -> VotingProgressView.SupportModel? { guard let chainAsset = chain.utilityAsset(), let supportThreshold = supportAndVotes.supportFunction?.calculateThreshold(for: currentBlock) else { @@ -314,7 +314,9 @@ final class ReferendumsModelFactory { preferredLanguages: locale.rLanguages ) - return .init(title: text, icon: image) + let titleIcon = TitleIconViewModel(title: text, icon: image) + + return .init(titleIcon: titleIcon, completed: isCompleted) } private func createVotingApprovalProgressViewModel( diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index b12a3c8498..147e11aa6f 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -180,7 +180,7 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { let viewModelFactory = ReferendumsModelFactory( statusViewModelFactory: statusViewModelFactory, assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), - percentFormatter: NumberFormatter.percentHalfEven.localizableResource(), + percentFormatter: NumberFormatter.referendumPercent.localizableResource(), indexFormatter: NumberFormatter.index.localizableResource() ) From 56ceb9ee6051ae88675792f9b4e73ab79c476a0b Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 12:44:40 +0500 Subject: [PATCH 113/229] hide threshold when reached --- .../Model/ReferendumAccountVoteLocal.swift | 18 ++++++++++++++++++ .../ReferendumDisplayStringFactory.swift | 2 +- .../ViewModel/ReferendumsModelFactory.swift | 8 +++----- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift index dc17b026d2..c38e52ffc2 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumAccountVoteLocal.swift @@ -5,6 +5,24 @@ enum ReferendumAccountVoteLocal { case split(ConvictionVoting.AccountVoteSplit) case standard(ConvictionVoting.AccountVoteStandard) + var hasAyeVotes: Bool { + switch self { + case let .split(voting): + return voting.aye > 0 + case let .standard(voting): + return voting.vote.aye + } + } + + var hasNayVotes: Bool { + switch self { + case let .split(voting): + return voting.nay > 0 + case let .standard(voting): + return !voting.vote.aye + } + } + /// post conviction votes for referendum var ayes: BigUInt { switch self { diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift index c2b383604f..ed1a6c1106 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift @@ -69,7 +69,7 @@ extension ReferendumDisplayStringFactoryProtocol { let voteSideString: String let voteSideStyle: YourVoteView.Style - if vote.ayes > 0 { + if vote.hasAyeVotes { voteSideString = R.string.localizable.governanceAye(preferredLanguages: locale.rLanguages) voteSideStyle = .ayeInverse } else { diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 134f7b253a..2d81aa0177 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -143,9 +143,7 @@ final class ReferendumsModelFactory { chainAsset: AssetModel?, locale: Locale ) -> YourVotesView.Model? { - guard let votes = votes, - let chainAsset = chainAsset, - votes.ayes + votes.nays > 0 else { + guard let votes = votes, let chainAsset = chainAsset else { return nil } @@ -164,12 +162,12 @@ final class ReferendumsModelFactory { preferredLanguages: locale.rLanguages ) } - let ayesModel = votes.ayes > 0 ? YourVoteView.Model( + let ayesModel = votes.hasAyeVotes ? YourVoteView.Model( title: Strings.governanceAye(preferredLanguages: locale.rLanguages).uppercased(), description: formatVotes(votes.ayes), style: .aye ) : nil - let naysModel = votes.nays > 0 ? YourVoteView.Model( + let naysModel = votes.hasNayVotes ? YourVoteView.Model( title: Strings.governanceNay(preferredLanguages: locale.rLanguages).uppercased(), description: formatVotes(votes.nays), style: .nay From 96847a07d17458a73fc719baec0f46a0afc03a76 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 12:53:32 +0500 Subject: [PATCH 114/229] add votes sorting --- .../ReferendumVotersPresenter.swift | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift index cb125f793d..b232628e7d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift @@ -46,11 +46,20 @@ final class ReferendumVotersPresenter { let viewModels: [ReferendumVotersViewModel] = model.voters.filter { voter in switch type { case .ayes: - return voter.vote.ayes > 0 + return voter.vote.hasAyeVotes case .nays: - return voter.vote.nays > 0 + return voter.vote.hasNayVotes } - }.compactMap { voter in + } + .sorted { + switch type { + case .ayes: + return $0.vote.ayes > $1.vote.ayes + case .nays: + return $0.vote.nays > $1.vote.nays + } + } + .compactMap { voter in guard let address = try? voter.accountId.toAddress(using: chain.chainFormat) else { return nil } From 29439bf1271bc399bc937fd0b09398e24fc04f86 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 15:17:50 +0500 Subject: [PATCH 115/229] add default referendum title --- .../ReferendumDetailsViewFactory.swift | 1 + .../ViewModel/ReferendumsModelFactory.swift | 35 ++++++++++++++++--- .../Parent/VoteChildPresenterFactory.swift | 3 ++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 6ea08dd978..0540a155e3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -33,6 +33,7 @@ struct ReferendumDetailsViewFactory { let indexFormatter = NumberFormatter.index.localizableResource() let referendumViewModelFactory = ReferendumsModelFactory( + referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactory(indexFormatter: indexFormatter), statusViewModelFactory: statusViewModelFactory, assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), percentFormatter: NumberFormatter.referendumPercent.localizableResource(), diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 2d81aa0177..2e9dc1b2ba 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -43,13 +43,16 @@ final class ReferendumsModelFactory { let localizedPercentFormatter: LocalizableResource let localizedIndexFormatter: LocalizableResource let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol + let referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol init( + referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol, statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol, assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, percentFormatter: LocalizableResource, indexFormatter: LocalizableResource ) { + self.referendumMetadataViewModelFactory = referendumMetadataViewModelFactory self.statusViewModelFactory = statusViewModelFactory self.assetBalanceFormatterFactory = assetBalanceFormatterFactory localizedPercentFormatter = percentFormatter @@ -71,11 +74,17 @@ final class ReferendumsModelFactory { from: NSNumber(value: params.referendum.index) ) + let referendumTitle = referendumMetadataViewModelFactory.createTitle( + for: params.referendum, + metadata: params.metadata, + locale: locale + ) + return .init( referendumInfo: .init( status: status, time: nil, - title: params.metadata?.name ?? "", + title: referendumTitle, track: nil, referendumNumber: referendumNumber ), @@ -124,11 +133,17 @@ final class ReferendumsModelFactory { from: NSNumber(value: params.referendum.index) ) + let referendumTitle = referendumMetadataViewModelFactory.createTitle( + for: params.referendum, + metadata: params.metadata, + locale: locale + ) + return .init( referendumInfo: .init( status: .init(name: title.uppercased(), kind: .neutral), time: timeModel?.viewModel, - title: params.metadata?.name ?? "", + title: referendumTitle, track: track, referendumNumber: referendumNumber ), @@ -218,11 +233,17 @@ final class ReferendumsModelFactory { let indexFormatter = localizedIndexFormatter.value(for: locale) let referendumNumber = indexFormatter.string(from: NSNumber(value: params.referendum.index)) + let referendumTitle = referendumMetadataViewModelFactory.createTitle( + for: params.referendum, + metadata: params.metadata, + locale: locale + ) + return .init( referendumInfo: .init( status: .init(name: statusName.uppercased(), kind: statusKind), time: timeModel?.viewModel, - title: params.metadata?.name, + title: referendumTitle, track: track, referendumNumber: referendumNumber ), @@ -255,11 +276,17 @@ final class ReferendumsModelFactory { from: NSNumber(value: params.referendum.index) ) + let referendumTitle = referendumMetadataViewModelFactory.createTitle( + for: params.referendum, + metadata: params.metadata, + locale: locale + ) + return .init( referendumInfo: .init( status: .init(name: title.uppercased(), kind: .positive), time: timeModel?.viewModel, - title: params.metadata?.name, + title: referendumTitle, track: nil, referendumNumber: referendumNumber ), diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index 147e11aa6f..973df71b55 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -177,7 +177,10 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { let statusViewModelFactory = ReferendumStatusViewModelFactory() + let indexFormatter = NumberFormatter.index.localizableResource() + let viewModelFactory = ReferendumsModelFactory( + referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactory(indexFormatter: indexFormatter), statusViewModelFactory: statusViewModelFactory, assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), percentFormatter: NumberFormatter.referendumPercent.localizableResource(), From bbf30772164332c019d79cd81c4cd887b3432da1 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 15:23:23 +0500 Subject: [PATCH 116/229] update time on referendum change --- .../ReferendumDetails/ReferendumDetailsPresenter.swift | 1 + .../Vote/Governance/Referendums/ReferendumsPresenter.swift | 2 ++ 2 files changed, 3 insertions(+) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index af5091cc3f..084e563107 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -364,6 +364,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol provideReferendumInfoViewModel() provideVotingDetails() provideTitleViewModel() + updateTimerIfNeeded() } func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 62087415d5..27d8eee956 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -223,7 +223,9 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { func didReceiveReferendums(_ referendums: [ReferendumLocal]) { self.referendums = referendums.sorted(by: { $0.index < $1.index }) + updateView() + updateTimeModels() } func didReceiveSelectedChain(_ chain: ChainModel) { From ad8fc79ffcd81b2726b8d6288e4d62c18e7cee96 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 16:04:47 +0500 Subject: [PATCH 117/229] gov2 full details call --- .../Operation/Gov2ActionOperationFactory.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift index 02affaad19..d59916fd3a 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift @@ -20,7 +20,8 @@ final class Gov2ActionOperationFactory { requestFactory: StorageRequestFactoryProtocol, connection: JSONRPCEngine ) -> CompoundOperationWrapper>?> { - let callFetchClosure: (Data) -> CompoundOperationWrapper>?> = { hash in + let callFetchClosure: (Data) -> CompoundOperationWrapper>?> + callFetchClosure = { hash in let statusKeyParams: () throws -> [BytesCodable] = { [BytesCodable(wrappedValue: hash)] } @@ -36,7 +37,7 @@ final class Gov2ActionOperationFactory { let callKeyParams: () throws -> [Preimage.PreimageKey] = { let status = try statusFetchWrapper.targetOperation.extractNoCancellableResultData().first?.value - guard let length = status?.length else { + guard let length = status?.length, length <= Self.maxFetchCallSize else { return [] } @@ -56,7 +57,13 @@ final class Gov2ActionOperationFactory { let callKeys = try callKeyParams() guard !callKeys.isEmpty else { - return nil + let optStatus = try statusFetchWrapper.targetOperation.extractNoCancellableResultData().first?.value + + if let length = optStatus?.length { + return length > Self.maxFetchCallSize ? .tooLong : nil + } else { + return nil + } } let responses = try callFetchWrapper.targetOperation.extractNoCancellableResultData() From 22b6706d86c793467d910e8cf9de6512ff6deebc Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 17:02:04 +0500 Subject: [PATCH 118/229] add referendums sorting by time --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../Governance/Model/ReferendumsSorting.swift | 67 +++++++++++++++++++ .../Referendums/ReferendumsPresenter.swift | 25 ++++++- .../Parent/VoteChildPresenterFactory.swift | 1 + 4 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Model/ReferendumsSorting.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 631cdecaf6..4ba2208944 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -683,6 +683,7 @@ 843461CD26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461CC26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift */; }; 843461CF26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461CE26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift */; }; 843461D126E2641500DCE0CD /* SubqueryRewardOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461D026E2641500DCE0CD /* SubqueryRewardOperationFactory.swift */; }; + 843461E8290BF14400379936 /* ReferendumsSorting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461E7290BF14400379936 /* ReferendumsSorting.swift */; }; 8434C9E425401EF3009E4191 /* TransactionHistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */; }; 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */; }; 8434C9EA2540AE51009E4191 /* ExtrinsicEraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */; }; @@ -3602,6 +3603,7 @@ 843461CC26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletRemoteHistoryFiltering.swift; sourceTree = ""; }; 843461CE26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscanHistoryItem+Wallet.swift"; sourceTree = ""; }; 843461D026E2641500DCE0CD /* SubqueryRewardOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubqueryRewardOperationFactory.swift; sourceTree = ""; }; + 843461E7290BF14400379936 /* ReferendumsSorting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsSorting.swift; sourceTree = ""; }; 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryItem.swift; sourceTree = ""; }; 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDTransactionHistoryItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicEraTests.swift; sourceTree = ""; }; @@ -11475,6 +11477,7 @@ 84880C4329026C3E00CADB06 /* ReferendumDelegatingLocal.swift */, 84880C452902781E00CADB06 /* ReferendumVotingLocal.swift */, 84F1D67029068F810050F4E3 /* GovernanceDApp.swift */, + 843461E7290BF14400379936 /* ReferendumsSorting.swift */, ); path = Model; sourceTree = ""; @@ -15641,6 +15644,7 @@ 8488ECDF258CE118004591CC /* PurchaseCompleted.swift in Sources */, 84AE7AA727D36E4D00495267 /* IconDetailsGenericView.swift in Sources */, 840BF22726C2C8A600E3A955 /* ChainSyncEvents.swift in Sources */, + 843461E8290BF14400379936 /* ReferendumsSorting.swift in Sources */, 843910C3253F39B100E3C217 /* WalletNetworkFacade+Storage.swift in Sources */, 84EC2D16276B92CB009B0BE1 /* DAppScriptResponse.swift in Sources */, F43A596A26D520E0005E973D /* EmptyStateViewCell.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumsSorting.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumsSorting.swift new file mode 100644 index 0000000000..3eaca363c4 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumsSorting.swift @@ -0,0 +1,67 @@ +import Foundation + +protocol ReferendumsSorting { + func compare(referendum1: ReferendumLocal, referendum2: ReferendumLocal) -> Bool +} + +final class ReferendumsTimeSortingProvider { + private func getGroup(for referendum: ReferendumLocal) -> UInt32 { + referendum.state.completed ? 1 : 0 + } + + private func getPositionForOngoing(referendum: ReferendumLocal) -> UInt32 { + switch referendum.state { + case let .preparing(model): + return model.timeoutAt + case let .deciding(model): + if let confirmation = model.confirmationUntil { + return confirmation + } else { + return model.rejectedAt + } + default: + return UInt32.max + } + } + + private func getPositionForCompleted(referendum: ReferendumLocal) -> UInt32 { + switch referendum.state { + case let .approved(model): + if let executeAt = model.whenEnactment { + return executeAt + } else { + return UInt32.max + } + default: + return UInt32.max + } + } +} + +extension ReferendumsTimeSortingProvider: ReferendumsSorting { + func compare(referendum1: ReferendumLocal, referendum2: ReferendumLocal) -> Bool { + let group1 = getGroup(for: referendum1) + let group2 = getGroup(for: referendum2) + + guard group1 == group2 else { + return group1 < group2 + } + + let pos1: UInt32 + let pos2: UInt32 + + if referendum1.state.completed { + pos1 = getPositionForCompleted(referendum: referendum1) + pos2 = getPositionForCompleted(referendum: referendum2) + } else { + pos1 = getPositionForOngoing(referendum: referendum1) + pos2 = getPositionForOngoing(referendum: referendum2) + } + + guard pos1 != pos2 else { + return referendum1.index > referendum2.index + } + + return pos1 < pos2 + } +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 27d8eee956..cbe75b31dd 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -9,6 +9,7 @@ final class ReferendumsPresenter { let wireframe: ReferendumsWireframeProtocol let viewModelFactory: ReferendumsModelFactoryProtocol let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol + let sorting: ReferendumsSorting let logger: LoggerProtocol private var freeBalance: BigUInt? @@ -35,6 +36,7 @@ final class ReferendumsPresenter { wireframe: ReferendumsWireframeProtocol, viewModelFactory: ReferendumsModelFactoryProtocol, statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol, + sorting: ReferendumsSorting, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol ) { @@ -42,10 +44,27 @@ final class ReferendumsPresenter { self.wireframe = wireframe self.viewModelFactory = viewModelFactory self.statusViewModelFactory = statusViewModelFactory + self.sorting = sorting self.logger = logger self.localizationManager = localizationManager } + func clearOnAssetSwitch() { + invalidateTimer() + + freeBalance = nil + price = nil + referendums = nil + referendumsMetadata = nil + votes = nil + blockNumber = nil + blockTime = nil + maxStatusTimeInterval = nil + timeModels = nil + + view?.update(model: .init(sections: [])) + } + private func provideChainBalance() { guard let chain = chain, let asset = chain.utilityAsset() else { return @@ -222,7 +241,7 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { } func didReceiveReferendums(_ referendums: [ReferendumLocal]) { - self.referendums = referendums.sorted(by: { $0.index < $1.index }) + self.referendums = referendums.sorted { sorting.compare(referendum1: $0, referendum2: $1) } updateView() updateTimeModels() @@ -283,8 +302,8 @@ extension ReferendumsPresenter: AssetSelectionDelegate { } chain = chainAsset.chain - freeBalance = nil - price = nil + + clearOnAssetSwitch() provideChainBalance() diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index 973df71b55..cad4526e90 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -192,6 +192,7 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { wireframe: wireframe, viewModelFactory: viewModelFactory, statusViewModelFactory: statusViewModelFactory, + sorting: ReferendumsTimeSortingProvider(), localizationManager: localizationManager, logger: logger ) From b183ae5225a6a8b3f828a15cbeef594185512c0f Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 17:10:13 +0500 Subject: [PATCH 119/229] ignore broken call --- .../Operation/Gov2ActionOperationFactory.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift index d59916fd3a..99a28eabad 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift @@ -13,7 +13,7 @@ final class Gov2ActionOperationFactory { self.operationQueue = operationQueue } - // switftlint:disable:next function_body_length + // swiftlint:disable:next function_body_length private func createCallFetchWrapper( dependingOn codingFactoryOperation: BaseOperation, referendum: ReferendumLocal, @@ -75,12 +75,16 @@ final class Gov2ActionOperationFactory { let decoder = try codingFactory.createDecoder(from: response.wrappedValue) - let call: RuntimeCall = try decoder.read( + let optCall: RuntimeCall? = try? decoder.read( of: GenericType.call.name, with: codingFactory.createRuntimeJsonContext().toRawContext() ) - return .concrete(call) + if let call = optCall { + return .concrete(call) + } else { + return nil + } } mappingOperation.addDependency(callFetchWrapper.targetOperation) From 265a7807488b2295ebf1978f62c4d6919a0e644b Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 17:28:43 +0500 Subject: [PATCH 120/229] fix status referenda end --- .../ViewModel/ReferendumStatusViewModelFactory.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift index 73ab6e05d8..76b94a27ba 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift @@ -102,6 +102,7 @@ final class ReferendumStatusViewModelFactory { } extension ReferendumStatusViewModelFactory: ReferendumStatusViewModelFactoryProtocol { + // swiftlint:disable:next function_body_length func createTimeViewModel( for referendum: ReferendumLocal, currentBlock: BlockNumber, @@ -121,7 +122,7 @@ extension ReferendumStatusViewModelFactory: ReferendumStatusViewModelFactoryProt return StatusTimeViewModel(viewModel: timeViewModel, timeInterval: nil) { _ in timeViewModel } - } else if currentBlock >= model.preparingPeriod { + } else if currentBlock >= model.preparingEnd { return createTimeViewModel( state: referendum.state, atBlock: max(currentBlock, model.timeoutAt), From 5b1e1f3fc76053effe16b0eb571773ada3a4ee65 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 18:17:16 +0500 Subject: [PATCH 121/229] refactoring --- novawallet.xcodeproj/project.pbxproj | 4 + .../Model/ReferendumVotingLocal.swift | 14 ++ .../Gov2OperationFactory+Protocol.swift | 219 +++++++++++++++++ .../Operation/Gov2OperationFactory.swift | 229 +----------------- .../ReferendumStatusViewModelFactory.swift | 1 + 5 files changed, 242 insertions(+), 225 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 4ba2208944..43957b9f42 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -684,6 +684,7 @@ 843461CF26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461CE26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift */; }; 843461D126E2641500DCE0CD /* SubqueryRewardOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461D026E2641500DCE0CD /* SubqueryRewardOperationFactory.swift */; }; 843461E8290BF14400379936 /* ReferendumsSorting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461E7290BF14400379936 /* ReferendumsSorting.swift */; }; + 843461EA290C04C400379936 /* Gov2OperationFactory+Protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */; }; 8434C9E425401EF3009E4191 /* TransactionHistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */; }; 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */; }; 8434C9EA2540AE51009E4191 /* ExtrinsicEraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */; }; @@ -3604,6 +3605,7 @@ 843461CE26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscanHistoryItem+Wallet.swift"; sourceTree = ""; }; 843461D026E2641500DCE0CD /* SubqueryRewardOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubqueryRewardOperationFactory.swift; sourceTree = ""; }; 843461E7290BF14400379936 /* ReferendumsSorting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsSorting.swift; sourceTree = ""; }; + 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gov2OperationFactory+Protocol.swift"; sourceTree = ""; }; 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryItem.swift; sourceTree = ""; }; 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDTransactionHistoryItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicEraTests.swift; sourceTree = ""; }; @@ -10201,6 +10203,7 @@ children = ( 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */, 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, + 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */, 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */, 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */, @@ -16593,6 +16596,7 @@ A07A987DE3047AF1A786D511 /* DAppListViewLayout.swift in Sources */, 8DF76D04C127E0048B253343 /* DAppListViewFactory.swift in Sources */, 848F8B242864448900204BC4 /* TransferSetupPresenterFactory+OnChain.swift in Sources */, + 843461EA290C04C400379936 /* Gov2OperationFactory+Protocol.swift in Sources */, 8402CC9E275B946100E5BF30 /* DAppItemViewCell.swift in Sources */, FFE19A19E5B4ED67A2C61951 /* DAppSearchProtocols.swift in Sources */, F88D85C73094F6A1FC494D87 /* DAppSearchWireframe.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift index 1d07d5e3ba..22d6c51fac 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift @@ -7,6 +7,20 @@ struct ReferendumAccountVotingDistribution { let priorLocks: [TrackIdLocal: ConvictionVoting.PriorLock] let maxVotesPerTrack: UInt32 + init( + votes: [ReferendumIdLocal: ReferendumAccountVoteLocal] = [:], + votedTracks: [TrackIdLocal: Set] = [:], + delegatings: [TrackIdLocal: ReferendumDelegatingLocal] = [:], + priorLocks: [TrackIdLocal: ConvictionVoting.PriorLock] = [:], + maxVotesPerTrack: UInt32 + ) { + self.votes = votes + self.votedTracks = votedTracks + self.delegatings = delegatings + self.priorLocks = priorLocks + self.maxVotesPerTrack = maxVotesPerTrack + } + func addingVote( _ vote: ReferendumAccountVoteLocal, referendumId: ReferendumIdLocal diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift new file mode 100644 index 0000000000..5bc6e96f78 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift @@ -0,0 +1,219 @@ +import Foundation +import SubstrateSdk +import RobinHood +import BigInt + +extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { + func fetchAllReferendumsWrapper( + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[ReferendumLocal]> { + let request = UnkeyedRemoteStorageRequest(storagePath: Referenda.referendumInfo) + + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let referendumWrapper: CompoundOperationWrapper<[ReferendumIndexKey: ReferendumInfo]> = + requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: request.storagePath, + factory: { try codingFactoryOperation.extractNoCancellableResultData() } + ) + + referendumWrapper.addDependency(operations: [codingFactoryOperation]) + + let additionalInfoWrapper = createAdditionalInfoWrapper( + from: connection, + runtimeProvider: runtimeProvider, + blockHash: nil + ) + + let enactmentsWrapper = createEnacmentTimeFetchWrapper( + dependingOn: referendumWrapper.targetOperation, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: nil + ) + + enactmentsWrapper.addDependency(wrapper: referendumWrapper) + + let mapOperation = createReferendumMapOperation( + dependingOn: referendumWrapper.targetOperation, + additionalInfoOperation: additionalInfoWrapper.targetOperation, + enactmentsOperation: enactmentsWrapper.targetOperation + ) + + mapOperation.addDependency(referendumWrapper.targetOperation) + mapOperation.addDependency(additionalInfoWrapper.targetOperation) + mapOperation.addDependency(enactmentsWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + referendumWrapper.allOperations + + additionalInfoWrapper.allOperations + enactmentsWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } + + func fetchReferendumWrapper( + for remoteReferendum: ReferendumInfo, + index: ReferendumIdLocal, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper { + let additionalInfoWrapper = createAdditionalInfoWrapper( + from: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + let referendumOperation = ClosureOperation<[ReferendumIndexKey: ReferendumInfo]> { + let referendumIndexKey = ReferendumIndexKey(referendumIndex: Referenda.ReferendumIndex(index)) + return [referendumIndexKey: remoteReferendum] + } + + let enactmentsWrapper = createEnacmentTimeFetchWrapper( + dependingOn: referendumOperation, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + enactmentsWrapper.addDependency(operations: [referendumOperation]) + + let mergeOperation = createReferendumMapOperation( + dependingOn: referendumOperation, + additionalInfoOperation: additionalInfoWrapper.targetOperation, + enactmentsOperation: enactmentsWrapper.targetOperation + ) + + mergeOperation.addDependency(referendumOperation) + mergeOperation.addDependency(additionalInfoWrapper.targetOperation) + mergeOperation.addDependency(enactmentsWrapper.targetOperation) + + let mapOperation = ClosureOperation { + guard let referendum = try mergeOperation.extractNoCancellableResultData().first else { + throw BaseOperationError.unexpectedDependentResult + } + + return referendum + } + + mapOperation.addDependency(mergeOperation) + + let dependencies = [referendumOperation] + additionalInfoWrapper.allOperations + + enactmentsWrapper.allOperations + [mergeOperation] + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } + + func fetchAccountVotesWrapper( + for accountId: AccountId, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let request = MapRemoteStorageRequest(storagePath: ConvictionVoting.votingFor) { + BytesCodable(wrappedValue: accountId) + } + + let votesWrapper: CompoundOperationWrapper<[ConvictionVoting.VotingForKey: ConvictionVoting.Voting]> = + requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: ConvictionVoting.votingFor, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + at: blockHash + ) + + votesWrapper.addDependency(operations: [codingFactoryOperation]) + + let maxVotesOperation = createMaxVotesOperation(dependingOn: codingFactoryOperation) + maxVotesOperation.addDependency(codingFactoryOperation) + + let mappingOperation = ClosureOperation { + let voting = try votesWrapper.targetOperation.extractNoCancellableResultData() + let maxVotes = try maxVotesOperation.extractNoCancellableResultData() + + let initVotingLocal = ReferendumAccountVotingDistribution(maxVotesPerTrack: maxVotes) + + return voting.reduce(initVotingLocal) { resultVoting, votingKeyValue in + let voting = votingKeyValue.value + let track = TrackIdLocal(votingKeyValue.key.trackId) + switch voting { + case let .casting(castingVoting): + return castingVoting.votes.reduce(resultVoting) { result, vote in + let newResult = result.addingReferendum(ReferendumIdLocal(vote.pollIndex), track: track) + + guard let localVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { + return newResult + } + + return newResult.addingVote(localVote, referendumId: ReferendumIdLocal(vote.pollIndex)) + }.addingPriorLock(castingVoting.prior, track: track) + case let .delegating(delegatingVoting): + let delegatingLocal = ReferendumDelegatingLocal(remote: delegatingVoting) + return resultVoting.addingDelegating(delegatingLocal, trackId: track) + case .unknown: + return resultVoting + } + } + } + + mappingOperation.addDependency(votesWrapper.targetOperation) + mappingOperation.addDependency(maxVotesOperation) + + let dependencies = [codingFactoryOperation, maxVotesOperation] + votesWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } + + func fetchVotersWrapper( + for referendumIndex: ReferendumIdLocal, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[ReferendumVoterLocal]> { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let request = UnkeyedRemoteStorageRequest(storagePath: ConvictionVoting.votingFor) + + let votesWrapper: CompoundOperationWrapper<[ConvictionVoting.VotingForKey: ConvictionVoting.Voting]> = + requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: ConvictionVoting.votingFor, + factory: { try codingFactoryOperation.extractNoCancellableResultData() } + ) + + votesWrapper.addDependency(operations: [codingFactoryOperation]) + + let mappingOperation = ClosureOperation<[ReferendumVoterLocal]> { + let votesResult = try votesWrapper.targetOperation.extractNoCancellableResultData() + + return votesResult.compactMap { keyValue in + let accountId = keyValue.key.accountId + let voting = keyValue.value + + switch voting { + case let .casting(castingVoting): + guard + let vote = castingVoting.votes.first(where: { $0.pollIndex == referendumIndex }), + let accountVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { + return nil + } + + return ReferendumVoterLocal(accountId: accountId, vote: accountVote) + case .delegating, .unknown: + return nil + } + } + } + + mappingOperation.addDependency(votesWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + votesWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 16b703b0cd..56b2843e5b 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -32,7 +32,7 @@ final class Gov2OperationFactory { self.requestFactory = requestFactory } - private func createEnacmentTimeFetchWrapper( + func createEnacmentTimeFetchWrapper( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, @@ -84,7 +84,7 @@ final class Gov2OperationFactory { return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } - private func createReferendumMapOperation( + func createReferendumMapOperation( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, additionalInfoOperation: BaseOperation, enactmentsOperation: BaseOperation<[ReferendumIdLocal: BlockNumber]> @@ -110,7 +110,7 @@ final class Gov2OperationFactory { } } - private func createAdditionalInfoWrapper( + func createAdditionalInfoWrapper( from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockHash: Data? @@ -171,7 +171,7 @@ final class Gov2OperationFactory { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) } - private func createMaxVotesOperation( + func createMaxVotesOperation( dependingOn codingFactoryOperation: BaseOperation ) -> BaseOperation { let maxVotesOperation = PrimitiveConstantOperation(path: ConvictionVoting.maxVotes) @@ -186,224 +186,3 @@ final class Gov2OperationFactory { return maxVotesOperation } } - -extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { - func fetchAllReferendumsWrapper( - from connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol - ) -> CompoundOperationWrapper<[ReferendumLocal]> { - let request = UnkeyedRemoteStorageRequest(storagePath: Referenda.referendumInfo) - - let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - - let referendumWrapper: CompoundOperationWrapper<[ReferendumIndexKey: ReferendumInfo]> = - requestFactory.queryByPrefix( - engine: connection, - request: request, - storagePath: request.storagePath, - factory: { try codingFactoryOperation.extractNoCancellableResultData() } - ) - - referendumWrapper.addDependency(operations: [codingFactoryOperation]) - - let additionalInfoWrapper = createAdditionalInfoWrapper( - from: connection, - runtimeProvider: runtimeProvider, - blockHash: nil - ) - - let enactmentsWrapper = createEnacmentTimeFetchWrapper( - dependingOn: referendumWrapper.targetOperation, - connection: connection, - runtimeProvider: runtimeProvider, - blockHash: nil - ) - - enactmentsWrapper.addDependency(wrapper: referendumWrapper) - - let mapOperation = createReferendumMapOperation( - dependingOn: referendumWrapper.targetOperation, - additionalInfoOperation: additionalInfoWrapper.targetOperation, - enactmentsOperation: enactmentsWrapper.targetOperation - ) - - mapOperation.addDependency(referendumWrapper.targetOperation) - mapOperation.addDependency(additionalInfoWrapper.targetOperation) - mapOperation.addDependency(enactmentsWrapper.targetOperation) - - let dependencies = [codingFactoryOperation] + referendumWrapper.allOperations + - additionalInfoWrapper.allOperations + enactmentsWrapper.allOperations - - return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) - } - - func fetchReferendumWrapper( - for remoteReferendum: ReferendumInfo, - index: ReferendumIdLocal, - connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol, - blockHash: Data? - ) -> CompoundOperationWrapper { - let additionalInfoWrapper = createAdditionalInfoWrapper( - from: connection, - runtimeProvider: runtimeProvider, - blockHash: blockHash - ) - - let referendumOperation = ClosureOperation<[ReferendumIndexKey: ReferendumInfo]> { - let referendumIndexKey = ReferendumIndexKey(referendumIndex: Referenda.ReferendumIndex(index)) - return [referendumIndexKey: remoteReferendum] - } - - let enactmentsWrapper = createEnacmentTimeFetchWrapper( - dependingOn: referendumOperation, - connection: connection, - runtimeProvider: runtimeProvider, - blockHash: blockHash - ) - - enactmentsWrapper.addDependency(operations: [referendumOperation]) - - let mergeOperation = createReferendumMapOperation( - dependingOn: referendumOperation, - additionalInfoOperation: additionalInfoWrapper.targetOperation, - enactmentsOperation: enactmentsWrapper.targetOperation - ) - - mergeOperation.addDependency(referendumOperation) - mergeOperation.addDependency(additionalInfoWrapper.targetOperation) - mergeOperation.addDependency(enactmentsWrapper.targetOperation) - - let mapOperation = ClosureOperation { - guard let referendum = try mergeOperation.extractNoCancellableResultData().first else { - throw BaseOperationError.unexpectedDependentResult - } - - return referendum - } - - mapOperation.addDependency(mergeOperation) - - let dependencies = [referendumOperation] + additionalInfoWrapper.allOperations + - enactmentsWrapper.allOperations + [mergeOperation] - - return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) - } - - func fetchAccountVotesWrapper( - for accountId: AccountId, - from connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol, - blockHash: Data? - ) -> CompoundOperationWrapper { - let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - - let request = MapRemoteStorageRequest(storagePath: ConvictionVoting.votingFor) { - BytesCodable(wrappedValue: accountId) - } - - let votesWrapper: CompoundOperationWrapper<[ConvictionVoting.VotingForKey: ConvictionVoting.Voting]> = - requestFactory.queryByPrefix( - engine: connection, - request: request, - storagePath: ConvictionVoting.votingFor, - factory: { try codingFactoryOperation.extractNoCancellableResultData() }, - at: blockHash - ) - - votesWrapper.addDependency(operations: [codingFactoryOperation]) - - let maxVotesOperation = createMaxVotesOperation(dependingOn: codingFactoryOperation) - maxVotesOperation.addDependency(codingFactoryOperation) - - let mappingOperation = ClosureOperation { - let voting = try votesWrapper.targetOperation.extractNoCancellableResultData() - let maxVotes = try maxVotesOperation.extractNoCancellableResultData() - - let initVotingLocal = ReferendumAccountVotingDistribution( - votes: [:], - votedTracks: [:], - delegatings: [:], - priorLocks: [:], - maxVotesPerTrack: maxVotes - ) - - return voting.reduce(initVotingLocal) { resultVoting, votingKeyValue in - let voting = votingKeyValue.value - let track = TrackIdLocal(votingKeyValue.key.trackId) - switch voting { - case let .casting(castingVoting): - return castingVoting.votes.reduce(resultVoting) { result, vote in - let newResult = result.addingReferendum(ReferendumIdLocal(vote.pollIndex), track: track) - - guard let localVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { - return newResult - } - - return newResult.addingVote(localVote, referendumId: ReferendumIdLocal(vote.pollIndex)) - }.addingPriorLock(castingVoting.prior, track: track) - case let .delegating(delegatingVoting): - let delegatingLocal = ReferendumDelegatingLocal(remote: delegatingVoting) - return resultVoting.addingDelegating(delegatingLocal, trackId: track) - case .unknown: - return resultVoting - } - } - } - - mappingOperation.addDependency(votesWrapper.targetOperation) - mappingOperation.addDependency(maxVotesOperation) - - let dependencies = [codingFactoryOperation, maxVotesOperation] + votesWrapper.allOperations - - return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) - } - - func fetchVotersWrapper( - for referendumIndex: ReferendumIdLocal, - from connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol - ) -> CompoundOperationWrapper<[ReferendumVoterLocal]> { - let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - - let request = UnkeyedRemoteStorageRequest(storagePath: ConvictionVoting.votingFor) - - let votesWrapper: CompoundOperationWrapper<[ConvictionVoting.VotingForKey: ConvictionVoting.Voting]> = - requestFactory.queryByPrefix( - engine: connection, - request: request, - storagePath: ConvictionVoting.votingFor, - factory: { try codingFactoryOperation.extractNoCancellableResultData() } - ) - - votesWrapper.addDependency(operations: [codingFactoryOperation]) - - let mappingOperation = ClosureOperation<[ReferendumVoterLocal]> { - let votesResult = try votesWrapper.targetOperation.extractNoCancellableResultData() - - return votesResult.compactMap { keyValue in - let accountId = keyValue.key.accountId - let voting = keyValue.value - - switch voting { - case let .casting(castingVoting): - guard - let vote = castingVoting.votes.first(where: { $0.pollIndex == referendumIndex }), - let accountVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { - return nil - } - - return ReferendumVoterLocal(accountId: accountId, vote: accountVote) - case .delegating, .unknown: - return nil - } - } - } - - mappingOperation.addDependency(votesWrapper.targetOperation) - - let dependencies = [codingFactoryOperation] + votesWrapper.allOperations - - return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) - } -} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift index 76b94a27ba..12ffb1a97d 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift @@ -28,6 +28,7 @@ extension ReferendumStatusViewModelFactoryProtocol { } final class ReferendumStatusViewModelFactory { + // swiftlint:disable:next function_parameter_count private func createTimeViewModel( state: ReferendumStateLocal, atBlock: Moment, From 383e2a759720187fe66877635e6379a30da1d952 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 21:45:14 +0500 Subject: [PATCH 122/229] in queue formatting --- .../Referenda/Referenda+CodingPath.swift | 4 + .../Types/Referenda/ReferendaTrackInfo.swift | 12 +++ .../Model/GovernanceSharedState.swift | 5 +- .../Governance/Model/ReferendumLocal.swift | 6 ++ .../Operation/Gov2LocalMappingFactory.swift | 35 ++++++-- .../Gov2OperationFactory+Protocol.swift | 30 ++++++- .../Operation/Gov2OperationFactory.swift | 84 ++++++++++++++++++- .../ReferendumDetailsViewFactory.swift | 3 +- .../ReferendumVotersViewFactory.swift | 6 +- .../ViewModel/ReferendumsModelFactory.swift | 42 +++++++++- .../Parent/VoteChildPresenterFactory.swift | 8 +- novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 13 files changed, 215 insertions(+), 22 deletions(-) diff --git a/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift b/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift index 6a61391fd1..49e40f465b 100644 --- a/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift +++ b/novawallet/Common/Substrate/Types/Referenda/Referenda+CodingPath.swift @@ -5,6 +5,10 @@ extension Referenda { StorageCodingPath(moduleName: "Referenda", itemName: "ReferendumInfoFor") } + static var trackQueue: StorageCodingPath { + StorageCodingPath(moduleName: "Referenda", itemName: "TrackQueue") + } + static var tracks: ConstantCodingPath { ConstantCodingPath(moduleName: "Referenda", constantName: "Tracks") } diff --git a/novawallet/Common/Substrate/Types/Referenda/ReferendaTrackInfo.swift b/novawallet/Common/Substrate/Types/Referenda/ReferendaTrackInfo.swift index dfbd2b894d..74f34da5f4 100644 --- a/novawallet/Common/Substrate/Types/Referenda/ReferendaTrackInfo.swift +++ b/novawallet/Common/Substrate/Types/Referenda/ReferendaTrackInfo.swift @@ -26,4 +26,16 @@ extension Referenda { info = try container.decode(TrackInfo.self) } } + + struct TrackQueueItem: Decodable { + let referendum: Referenda.ReferendumIndex + let votes: BigUInt + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + + referendum = try container.decode(StringScaleMapper.self).value + votes = try container.decode(StringScaleMapper.self).value + } + } } diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index a7283049c2..1e0a8a844c 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -56,7 +56,10 @@ final class GovernanceSharedState { return } - let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) + let operationFactory = Gov2OperationFactory( + requestFactory: requestFactory, + operationQueue: OperationManagerFacade.sharedDefaultQueue + ) subscriptionFactory = Gov2SubscriptionFactory( chainId: chainId, diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 5603f07d7c..bcad25771a 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -129,6 +129,11 @@ enum ReferendumStateLocal { } } + struct InQueuePosition { + let index: Int + let total: Int + } + struct Preparing { let track: GovernanceTrackLocal let proposal: SupportPallet.Bounded> @@ -138,6 +143,7 @@ enum ReferendumStateLocal { let preparingPeriod: Moment let timeoutPeriod: Moment let inQueue: Bool + let inQueuePosition: InQueuePosition? var preparingEnd: BlockNumber { since + preparingPeriod diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index b1eb427447..5cd873dccb 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -49,8 +49,10 @@ final class Gov2LocalMappingFactory { private func createPreparingState( from status: ReferendumInfo.OngoingStatus, + index: Referenda.ReferendumIndex, track: Referenda.TrackInfo, - additionalInfo: Gov2OperationFactory.AdditionalInfo + additionalInfo: Gov2OperationFactory.AdditionalInfo, + trackQueue: [Referenda.TrackQueueItem]? ) -> ReferendumStateLocal { let approvalFunction = Gov2LocalDecidingFunction( curve: track.minApproval, @@ -75,6 +77,17 @@ final class Gov2LocalMappingFactory { let localTrack = GovernanceTrackLocal(trackId: status.track, name: track.name) + let inQueuePosition: ReferendumStateLocal.InQueuePosition? + + if + status.inQueue, + let queue = trackQueue, + let position = queue.firstIndex(where: { $0.referendum == index }) { + inQueuePosition = .init(index: position, total: queue.count) + } else { + inQueuePosition = nil + } + let preparing = ReferendumStateLocal.Preparing( track: localTrack, proposal: status.proposal, @@ -83,7 +96,8 @@ final class Gov2LocalMappingFactory { since: status.submitted, preparingPeriod: track.preparePeriod, timeoutPeriod: additionalInfo.undecidingTimeout, - inQueue: status.inQueue + inQueue: status.inQueue, + inQueuePosition: inQueuePosition ) return .preparing(model: preparing) @@ -92,7 +106,8 @@ final class Gov2LocalMappingFactory { private func createOngoingReferendumState( from status: ReferendumInfo.OngoingStatus, index: Referenda.ReferendumIndex, - additionalInfo: Gov2OperationFactory.AdditionalInfo + additionalInfo: Gov2OperationFactory.AdditionalInfo, + trackQueue: [Referenda.TrackQueueItem]? ) -> ReferendumLocal? { guard let track = additionalInfo.tracks[status.track] else { return nil @@ -110,8 +125,10 @@ final class Gov2LocalMappingFactory { } else { state = createPreparingState( from: status, + index: index, track: track, - additionalInfo: additionalInfo + additionalInfo: additionalInfo, + trackQueue: trackQueue ) } @@ -123,11 +140,17 @@ final class Gov2LocalMappingFactory { referendum: ReferendumInfo, index: Referenda.ReferendumIndex, additionalInfo: Gov2OperationFactory.AdditionalInfo, - enactmentBlock: BlockNumber? + enactmentBlock: BlockNumber?, + inQueueState: [Referenda.TrackId: [Referenda.TrackQueueItem]] ) -> ReferendumLocal? { switch referendum { case let .ongoing(status): - return createOngoingReferendumState(from: status, index: index, additionalInfo: additionalInfo) + return createOngoingReferendumState( + from: status, + index: index, + additionalInfo: additionalInfo, + trackQueue: inQueueState[status.track] + ) case let .approved(status): let state: ReferendumStateLocal diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift index 5bc6e96f78..3e92debd20 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift @@ -37,18 +37,29 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { enactmentsWrapper.addDependency(wrapper: referendumWrapper) + let inQueueStateWrapper = createTrackQueueOperation( + dependingOn: referendumWrapper.targetOperation, + connection: connection, + runtimeProvider: runtimeProvider, + requestFactory: requestFactory + ) + + inQueueStateWrapper.addDependency(operations: [referendumWrapper.targetOperation]) + let mapOperation = createReferendumMapOperation( dependingOn: referendumWrapper.targetOperation, additionalInfoOperation: additionalInfoWrapper.targetOperation, - enactmentsOperation: enactmentsWrapper.targetOperation + enactmentsOperation: enactmentsWrapper.targetOperation, + inQueueOperation: inQueueStateWrapper.targetOperation ) mapOperation.addDependency(referendumWrapper.targetOperation) mapOperation.addDependency(additionalInfoWrapper.targetOperation) mapOperation.addDependency(enactmentsWrapper.targetOperation) + mapOperation.addDependency(inQueueStateWrapper.targetOperation) let dependencies = [codingFactoryOperation] + referendumWrapper.allOperations + - additionalInfoWrapper.allOperations + enactmentsWrapper.allOperations + additionalInfoWrapper.allOperations + inQueueStateWrapper.allOperations + enactmentsWrapper.allOperations return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } @@ -80,15 +91,26 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { enactmentsWrapper.addDependency(operations: [referendumOperation]) + let inQueueStateWrapper = createTrackQueueOperation( + dependingOn: referendumOperation, + connection: connection, + runtimeProvider: runtimeProvider, + requestFactory: requestFactory + ) + + inQueueStateWrapper.addDependency(operations: [referendumOperation]) + let mergeOperation = createReferendumMapOperation( dependingOn: referendumOperation, additionalInfoOperation: additionalInfoWrapper.targetOperation, - enactmentsOperation: enactmentsWrapper.targetOperation + enactmentsOperation: enactmentsWrapper.targetOperation, + inQueueOperation: inQueueStateWrapper.targetOperation ) mergeOperation.addDependency(referendumOperation) mergeOperation.addDependency(additionalInfoWrapper.targetOperation) mergeOperation.addDependency(enactmentsWrapper.targetOperation) + mergeOperation.addDependency(inQueueStateWrapper.targetOperation) let mapOperation = ClosureOperation { guard let referendum = try mergeOperation.extractNoCancellableResultData().first else { @@ -101,7 +123,7 @@ extension Gov2OperationFactory: ReferendumsOperationFactoryProtocol { mapOperation.addDependency(mergeOperation) let dependencies = [referendumOperation] + additionalInfoWrapper.allOperations + - enactmentsWrapper.allOperations + [mergeOperation] + enactmentsWrapper.allOperations + inQueueStateWrapper.allOperations + [mergeOperation] return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift index 56b2843e5b..ee56e89536 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift @@ -27,9 +27,11 @@ final class Gov2OperationFactory { } let requestFactory: StorageRequestFactoryProtocol + let operationQueue: OperationQueue - init(requestFactory: StorageRequestFactoryProtocol) { + init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { self.requestFactory = requestFactory + self.operationQueue = operationQueue } func createEnacmentTimeFetchWrapper( @@ -87,12 +89,14 @@ final class Gov2OperationFactory { func createReferendumMapOperation( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, additionalInfoOperation: BaseOperation, - enactmentsOperation: BaseOperation<[ReferendumIdLocal: BlockNumber]> + enactmentsOperation: BaseOperation<[ReferendumIdLocal: BlockNumber]>, + inQueueOperation: BaseOperation<[Referenda.TrackId: [Referenda.TrackQueueItem]]> ) -> BaseOperation<[ReferendumLocal]> { ClosureOperation<[ReferendumLocal]> { let remoteReferendums = try referendumOperation.extractNoCancellableResultData() let additionalInfo = try additionalInfoOperation.extractNoCancellableResultData() let enactments = try enactmentsOperation.extractNoCancellableResultData() + let inQueueState = try inQueueOperation.extractNoCancellableResultData() let mappingFactory = Gov2LocalMappingFactory() @@ -104,7 +108,8 @@ final class Gov2OperationFactory { referendum: remoteReferendum, index: Referenda.ReferendumIndex(referendumIndex), additionalInfo: additionalInfo, - enactmentBlock: enactments[referendumIndex] + enactmentBlock: enactments[referendumIndex], + inQueueState: inQueueState ) } } @@ -185,4 +190,77 @@ final class Gov2OperationFactory { return maxVotesOperation } + + func createTrackQueueOperation( + dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + requestFactory: StorageRequestFactoryProtocol + ) -> CompoundOperationWrapper<[Referenda.TrackId: [Referenda.TrackQueueItem]]> { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let fetchOperation: BaseOperation<[[Referenda.TrackId: [Referenda.TrackQueueItem]]]> = + OperationCombiningService(operationManager: OperationManager(operationQueue: operationQueue)) { + let referendums = try referendumOperation.extractNoCancellableResultData() + + let trackIdsList: [Referenda.TrackId] = referendums.compactMap { keyValue in + let referendum = keyValue.value + + switch referendum { + case let .ongoing(status): + if status.inQueue { + return status.track + } else { + return nil + } + default: + return nil + } + } + + let keyParams = Array(Set(trackIdsList).map { StringScaleMapper(value: $0) }) + + guard !keyParams.isEmpty else { return [] } + + let wrapper: CompoundOperationWrapper<[StorageResponse<[Referenda.TrackQueueItem]>]> = + requestFactory.queryItems( + engine: connection, + keyParams: { keyParams }, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: Referenda.trackQueue + ) + + let mappingOperation = ClosureOperation<[Referenda.TrackId: [Referenda.TrackQueueItem]]> { + let responses = try wrapper.targetOperation.extractNoCancellableResultData() + + let initValue = [Referenda.TrackId: [Referenda.TrackQueueItem]]() + return zip(keyParams, responses).reduce(into: initValue) { accum, trackQueue in + accum[trackQueue.0.value] = trackQueue.1.value + } + } + + mappingOperation.addDependency(wrapper.targetOperation) + + let result = CompoundOperationWrapper( + targetOperation: mappingOperation, + dependencies: wrapper.allOperations + ) + + return [result] + + }.longrunOperation() + + fetchOperation.addDependency(codingFactoryOperation) + + let mappingOperation = ClosureOperation<[Referenda.TrackId: [Referenda.TrackQueueItem]]> { + try fetchOperation.extractNoCancellableResultData().first ?? [:] + } + + mappingOperation.addDependency(fetchOperation) + + return CompoundOperationWrapper( + targetOperation: mappingOperation, + dependencies: [codingFactoryOperation, fetchOperation] + ) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 0540a155e3..aefddeb590 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -37,7 +37,8 @@ struct ReferendumDetailsViewFactory { statusViewModelFactory: statusViewModelFactory, assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), percentFormatter: NumberFormatter.referendumPercent.localizableResource(), - indexFormatter: indexFormatter + indexFormatter: indexFormatter, + quantityFormatter: NumberFormatter.quantity.localizableResource() ) let referendumStringFactory = ReferendumDisplayStringFactory() diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift index e7f990c5f7..dd30e7f082 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift @@ -71,7 +71,11 @@ struct ReferendumVotersViewFactory { operationManager: OperationManager(operationQueue: operationQueue) ) - let referendumsOperationFactory = Gov2OperationFactory(requestFactory: requestFactory) + let referendumsOperationFactory = Gov2OperationFactory( + requestFactory: requestFactory, + operationQueue: OperationManagerFacade.sharedDefaultQueue + ) + let identityOperationFactory = IdentityOperationFactory( requestFactory: requestFactory, emptyIdentitiesWhenNoStorage: true diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 2e9dc1b2ba..a4699100d4 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -42,6 +42,7 @@ final class ReferendumsModelFactory { let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol let localizedPercentFormatter: LocalizableResource let localizedIndexFormatter: LocalizableResource + let localizedQuantityFormatter: LocalizableResource let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol let referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol @@ -50,13 +51,15 @@ final class ReferendumsModelFactory { statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol, assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, percentFormatter: LocalizableResource, - indexFormatter: LocalizableResource + indexFormatter: LocalizableResource, + quantityFormatter: LocalizableResource ) { self.referendumMetadataViewModelFactory = referendumMetadataViewModelFactory self.statusViewModelFactory = statusViewModelFactory self.assetBalanceFormatterFactory = assetBalanceFormatterFactory localizedPercentFormatter = percentFormatter localizedIndexFormatter = indexFormatter + localizedQuantityFormatter = quantityFormatter } private func provideCommonReferendumCellViewModel( @@ -93,6 +96,33 @@ final class ReferendumsModelFactory { ) } + private func createInQueueFormatting( + for position: ReferendumStateLocal.InQueuePosition?, + locale: Locale + ) -> String { + if let position = position { + let formatter = localizedQuantityFormatter.value(for: locale) + let positionString = formatter.string(from: (position.index + 1) as NSNumber) ?? "" + let totalString = formatter.string(from: position.total as NSNumber) ?? "" + + let queueString = R.string.localizable.govInQueueCounter( + positionString, + totalString, + preferredLanguages: locale.rLanguages + ) + + let prefixTitle = R.string.localizable.governanceReferendumsStatusPreparingInqueue( + preferredLanguages: locale.rLanguages + ) + + return prefixTitle + " " + queueString + } else { + return R.string.localizable.governanceReferendumsStatusPreparingInqueue( + preferredLanguages: locale.rLanguages + ) + } + } + private func providePreparingReferendumCellViewModel( _ model: ReferendumStateLocal.Preparing, params: StatusParams, @@ -105,9 +135,13 @@ final class ReferendumsModelFactory { locale: locale ) - let title = model.inQueue ? - Strings.governanceReferendumsStatusPreparingInqueue(preferredLanguages: locale.rLanguages) : - Strings.governanceReferendumsStatusPreparing(preferredLanguages: locale.rLanguages) + let title: String + + if model.inQueue { + title = createInQueueFormatting(for: model.inQueuePosition, locale: locale) + } else { + title = Strings.governanceReferendumsStatusPreparing(preferredLanguages: locale.rLanguages) + } switch model.voting { case let .supportAndVotes(supportAndVotes): diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index cad4526e90..e488768604 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -107,7 +107,10 @@ final class VoteChildPresenterFactory { operationManager: OperationManager(operationQueue: operationQueue) ) - let referendumOperationFactory = Gov2OperationFactory(requestFactory: requestFactory) + let referendumOperationFactory = Gov2OperationFactory( + requestFactory: requestFactory, + operationQueue: OperationManagerFacade.sharedDefaultQueue + ) let serviceFactory = GovernanceServiceFactory( chainRegisty: chainRegistry, @@ -184,7 +187,8 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { statusViewModelFactory: statusViewModelFactory, assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), percentFormatter: NumberFormatter.referendumPercent.localizableResource(), - indexFormatter: NumberFormatter.index.localizableResource() + indexFormatter: NumberFormatter.index.localizableResource(), + quantityFormatter: NumberFormatter.quantity.localizableResource() ) let presenter = ReferendumsPresenter( diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index ce6e9bc5f9..d731cbf951 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1072,3 +1072,4 @@ "gov.stepped.decreasing" = "Stepped Decreasing"; "gov.reciprocal" = "Reciprocal"; "gov.unknown" = "Unknown"; +"gov.in.queue.counter" = "(%@ of %@)"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 66184f6d03..f1a73cb053 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1073,3 +1073,4 @@ "gov.stepped.decreasing" = "Ступенчатое убывание"; "gov.reciprocal" = "Обратное линейное убывание"; "gov.unknown" = "Неизвестно"; +"gov.in.queue.counter" = "(%@ из %@)"; From e0bbad0ff8a043f07ae78934d6806eb603be7e3f Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 22:04:52 +0500 Subject: [PATCH 123/229] fix referendum list jumps --- .../ReferendumDetailsProtocols.swift | 2 +- .../ReferendumDetailsViewController.swift | 2 +- .../View/ReferendumVotingStatusView.swift | 6 +-- .../View/Rows/TimelineRow.swift | 2 +- .../Timeline/ReferendumTimelineView.swift | 4 +- .../View/TrackTagsView.swift | 2 +- .../Governance/View/ReferendumInfoView.swift | 44 +++++++++++-------- .../ReferendumStatusViewModelFactory.swift | 6 +-- .../ViewModel/ReferendumTrackType.swift | 2 +- .../ViewModel/ReferendumsModelFactory.swift | 6 +-- .../ViewModel/StatusTimeViewModel.swift | 4 +- 11 files changed, 44 insertions(+), 36 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 4402ddffb2..818ca0e8c4 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -6,7 +6,7 @@ protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { func didReceive(yourVoteModel: YourVoteRow.Model?) func didReceive(requestedAmount: RequestedAmountRow.Model?) func didReceive(trackTagsModel: TrackTagsView.Model?) - func didReceive(activeTimeViewModel: ReferendumInfoView.Model.Time?) + func didReceive(activeTimeViewModel: ReferendumInfoView.Time?) func didReceive(shouldHideFullDetails: Bool) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index e24c8aafac..14677df7cb 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -151,7 +151,7 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { rootView.setFullDetails(hidden: shouldHideFullDetails, locale: localizationManager.selectedLocale) } - func didReceive(activeTimeViewModel: ReferendumInfoView.Model.Time?) { + func didReceive(activeTimeViewModel: ReferendumInfoView.Time?) { rootView.votingDetailsRow.statusView.bind(timeModel: activeTimeViewModel) rootView.timelineView.bind(activeTimeViewModel: activeTimeViewModel) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift index 02ecdc16a8..a0808d2b92 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumVotingStatusView.swift @@ -45,7 +45,7 @@ final class ReferendumVotingStatusView: UIView { extension ReferendumVotingStatusView { struct Model { let status: Status - let time: ReferendumInfoView.Model.Time? + let time: ReferendumInfoView.Time? let title: String? } @@ -59,7 +59,7 @@ extension ReferendumVotingStatusView { case negative case neutral - init(infoKind: ReferendumInfoView.Model.StatusKind) { + init(infoKind: ReferendumInfoView.StatusKind) { switch infoKind { case .positive: self = .positive @@ -86,7 +86,7 @@ extension ReferendumVotingStatusView { } } - func bind(timeModel: ReferendumInfoView.Model.Time?) { + func bind(timeModel: ReferendumInfoView.Time?) { if let time = timeModel { timeView.bind(viewModel: time.titleIcon) timeView.apply(style: time.isUrgent ? .activeTimeView : .timeView) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift index a62f1e85d1..195871586c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Rows/TimelineRow.swift @@ -30,7 +30,7 @@ final class TimelineRow: RoundedView, BindableView { contentView.bind(viewModel: viewModel) } - func bind(activeTimeViewModel: ReferendumInfoView.Model.Time?) { + func bind(activeTimeViewModel: ReferendumInfoView.Time?) { contentView.bind(activeTimeViewModel: activeTimeViewModel) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift index f14ca76221..f2d169edf3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/Timeline/ReferendumTimelineView.swift @@ -106,7 +106,7 @@ extension ReferendumTimelineView: BindableView { enum StatusSubtitle { case date(String) - case interval(ReferendumInfoView.Model.Time) + case interval(ReferendumInfoView.Time) } func bind(viewModel: [Model]) { @@ -114,7 +114,7 @@ extension ReferendumTimelineView: BindableView { setNeedsLayout() } - func bind(activeTimeViewModel: ReferendumInfoView.Model.Time?) { + func bind(activeTimeViewModel: ReferendumInfoView.Time?) { guard let activeView = statusViews.last as? GenericMultiValueView else { return } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift index c96d06a860..1a9f1bb703 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/TrackTagsView.swift @@ -47,7 +47,7 @@ final class TrackTagsView: UIView { extension TrackTagsView: BindableView { struct Model { - let titleIcon: ReferendumInfoView.Model.Track? + let titleIcon: ReferendumInfoView.Track? let referendumNumber: String? } diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift index acec0e1a63..6b4b15ca37 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -19,6 +19,7 @@ final class ReferendumInfoView: UIView { $0.iconDetailsView.detailsLabel.apply(style: .track) $0.backgroundView.apply(style: .referendum) $0.iconDetailsView.detailsLabel.numberOfLines = 1 + $0.backgroundView.cornerRadius = 7 } let numberLabel: BorderedLabelView = .create { @@ -26,6 +27,7 @@ final class ReferendumInfoView: UIView { $0.contentInsets = .init(top: 4, left: 6, bottom: 4, right: 8) $0.backgroundView.apply(style: .referendum) $0.titleLabel.numberOfLines = 1 + $0.backgroundView.cornerRadius = 7 } private var trackImageViewModel: ImageViewModelProtocol? @@ -63,11 +65,17 @@ final class ReferendumInfoView: UIView { trackInformation ] ) + content.setCustomSpacing(12, after: titleLabel) + addSubview(content) content.snp.makeConstraints { $0.edges.equalToSuperview() } + + trackInformation.snp.makeConstraints { + $0.height.equalTo(22.0) + } } } @@ -78,27 +86,27 @@ extension ReferendumInfoView { let title: String? let track: Track? let referendumNumber: String? + } - struct Time: Equatable { - let titleIcon: TitleIconViewModel - let isUrgent: Bool - } + struct Time: Equatable { + let titleIcon: TitleIconViewModel + let isUrgent: Bool + } - struct Track { - let title: String - let icon: ImageViewModelProtocol? - } + struct Track { + let title: String + let icon: ImageViewModelProtocol? + } - struct Status { - let name: String - let kind: StatusKind - } + struct Status { + let name: String + let kind: StatusKind + } - enum StatusKind { - case positive - case negative - case neutral - } + enum StatusKind { + case positive + case negative + case neutral } func bind(viewModel: Model) { @@ -144,7 +152,7 @@ extension ReferendumInfoView { } } - func bind(timeModel: Model.Time?) { + func bind(timeModel: Time?) { if let time = timeModel { timeView.bind(viewModel: time.titleIcon) timeView.apply(style: time.isUrgent ? .activeTimeView : .timeView) diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift index 12ffb1a97d..7a6eb13978 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift @@ -65,13 +65,13 @@ final class ReferendumStatusViewModelFactory { timeStringProvider: (String, [String]?) -> String, state: ReferendumStateLocal, locale: Locale - ) -> ReferendumInfoView.Model.Time? { + ) -> ReferendumInfoView.Time? { guard let localizedDaysHours = time.localizedDaysOrTime(for: locale) else { return nil } let timeString = timeStringProvider(localizedDaysHours, locale.rLanguages) let timeModel = isUrgent(state: state, time: time).map { isUrgent in - ReferendumInfoView.Model.Time( + ReferendumInfoView.Time( titleIcon: .init( title: timeString, icon: isUrgent ? R.image.iconFire() : R.image.iconLightPending() @@ -115,7 +115,7 @@ extension ReferendumStatusViewModelFactory: ReferendumStatusViewModelFactoryProt case let .preparing(model): if model.deposit == nil { let title = strings.governanceReferendumsTimeWaitingDeposit(preferredLanguages: locale.rLanguages) - let timeViewModel = ReferendumInfoView.Model.Time( + let timeViewModel = ReferendumInfoView.Time( titleIcon: .init(title: title, icon: R.image.iconLightPending()), isUrgent: false ) diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTrackType.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTrackType.swift index 5de4ad0623..0f5a83b741 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTrackType.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTrackType.swift @@ -80,7 +80,7 @@ enum ReferendumTrackType: String, CaseIterable, Equatable { from rawName: String, chain: ChainModel, locale: Locale - ) -> ReferendumInfoView.Model.Track { + ) -> ReferendumInfoView.Track { let type = ReferendumTrackType(rawValue: rawName) let title = type?.title(for: locale)?.uppercased() ?? rawName.replacingSnakeCase().uppercased() let icon = type?.imageViewModel(for: chain) diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index a4699100d4..379bfcabdf 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -63,7 +63,7 @@ final class ReferendumsModelFactory { } private func provideCommonReferendumCellViewModel( - status: ReferendumInfoView.Model.Status, + status: ReferendumInfoView.Status, params: StatusParams, locale: Locale ) -> ReferendumView.Model { @@ -251,7 +251,7 @@ final class ReferendumsModelFactory { let statusName = isPassing ? Strings.governanceReferendumsStatusPassing(preferredLanguages: locale.rLanguages) : Strings.governanceReferendumsStatusNotPassing(preferredLanguages: locale.rLanguages) - let statusKind: ReferendumInfoView.Model.StatusKind = isPassing ? .positive : .negative + let statusKind: ReferendumInfoView.StatusKind = isPassing ? .positive : .negative let yourVotesModel = createVotesViewModel( votes: params.votes, chainAsset: params.chainInfo.chain.utilityAsset(), @@ -493,7 +493,7 @@ extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { params: StatusParams, locale: Locale ) -> ReferendumView.Model { - let status: ReferendumInfoView.Model.Status + let status: ReferendumInfoView.Status switch state { case let .preparing(model): return providePreparingReferendumCellViewModel(model, params: params, locale: locale) diff --git a/novawallet/Modules/Vote/Governance/ViewModel/StatusTimeViewModel.swift b/novawallet/Modules/Vote/Governance/ViewModel/StatusTimeViewModel.swift index c24225e94f..5eafadd5f4 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/StatusTimeViewModel.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/StatusTimeViewModel.swift @@ -1,7 +1,7 @@ import Foundation struct StatusTimeViewModel { - let viewModel: ReferendumInfoView.Model.Time + let viewModel: ReferendumInfoView.Time let timeInterval: TimeInterval? - let updateModelClosure: (TimeInterval) -> ReferendumInfoView.Model.Time? + let updateModelClosure: (TimeInterval) -> ReferendumInfoView.Time? } From bc14b6760441dda91e81be37f50367ae5e15abb0 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 23:21:35 +0500 Subject: [PATCH 124/229] provide cached data to details --- .../ReferendumDetailsPresenter.swift | 6 +++++- .../ReferendumDetailsViewFactory.swift | 8 ++++++-- .../Referendums/ReferendumsPresenter.swift | 9 +++++++-- .../Referendums/ReferendumsProtocols.swift | 7 ++++++- .../Referendums/ReferendumsWireframe.swift | 15 +++++++++++++-- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 084e563107..613cc1237f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -39,6 +39,8 @@ final class ReferendumDetailsPresenter { init( referendum: ReferendumLocal, chain: ChainModel, + accountVotes: ReferendumAccountVoteLocal?, + metadata: ReferendumMetadataLocal?, interactor: ReferendumDetailsInteractorInputProtocol, wireframe: ReferendumDetailsWireframeProtocol, referendumViewModelFactory: ReferendumsModelFactoryProtocol, @@ -63,6 +65,8 @@ final class ReferendumDetailsPresenter { self.statusViewModelFactory = statusViewModelFactory self.displayAddressViewModelFactory = displayAddressViewModelFactory self.referendum = referendum + self.accountVotes = accountVotes + referendumMetadata = metadata self.chain = chain self.logger = logger self.localizationManager = localizationManager @@ -245,7 +249,7 @@ final class ReferendumDetailsPresenter { } private func provideFullDetailsViewModel() { - let shouldHide = actionDetails == nil + let shouldHide = actionDetails == nil || referendum.state.completed view?.didReceive(shouldHideFullDetails: shouldHide) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index aefddeb590..eb6fbe9251 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -5,8 +5,10 @@ import SoraFoundation struct ReferendumDetailsViewFactory { static func createView( - for referendum: ReferendumLocal, - state: GovernanceSharedState + for state: GovernanceSharedState, + referendum: ReferendumLocal, + accountVotes: ReferendumAccountVoteLocal?, + metadata: ReferendumMetadataLocal? ) -> ReferendumDetailsViewProtocol? { guard let currencyManager = CurrencyManager.shared, @@ -52,6 +54,8 @@ struct ReferendumDetailsViewFactory { let presenter = ReferendumDetailsPresenter( referendum: referendum, chain: chain, + accountVotes: accountVotes, + metadata: metadata, interactor: interactor, wireframe: wireframe, referendumViewModelFactory: referendumViewModelFactory, diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index cbe75b31dd..49e507d726 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -17,7 +17,7 @@ final class ReferendumsPresenter { private var price: PriceData? private var referendums: [ReferendumLocal]? private var referendumsMetadata: ReferendumMetadataMapping? - private var votes: [UInt: ReferendumAccountVoteLocal]? + private var votes: [ReferendumIdLocal: ReferendumAccountVoteLocal]? private var blockNumber: BlockNumber? private var blockTime: BlockTime? @@ -186,7 +186,12 @@ extension ReferendumsPresenter: ReferendumsPresenterProtocol { return } - wireframe.showReferendumDetails(from: view, referendum: referendum) + wireframe.showReferendumDetails( + from: view, + referendum: referendum, + accountVotes: votes?[referendum.index], + metadata: referendumsMetadata?[referendum.index] + ) } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 981c0a843d..733ebfe731 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -41,5 +41,10 @@ protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, Commo selectedChainAssetId: ChainAssetId? ) - func showReferendumDetails(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) + func showReferendumDetails( + from view: ControllerBackedProtocol?, + referendum: ReferendumLocal, + accountVotes: ReferendumAccountVoteLocal?, + metadata: ReferendumMetadataLocal? + ) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index dbaac6d3ee..c38fcdb88d 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -31,8 +31,19 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { view?.controller.present(navigationController, animated: true, completion: nil) } - func showReferendumDetails(from view: ControllerBackedProtocol?, referendum: ReferendumLocal) { - guard let detailsView = ReferendumDetailsViewFactory.createView(for: referendum, state: state) else { + func showReferendumDetails( + from view: ControllerBackedProtocol?, + referendum: ReferendumLocal, + accountVotes: ReferendumAccountVoteLocal?, + metadata: ReferendumMetadataLocal? + ) { + guard + let detailsView = ReferendumDetailsViewFactory.createView( + for: state, + referendum: referendum, + accountVotes: accountVotes, + metadata: metadata + ) else { return } From 64084bc5c83cda865aff5cd9322f57d8c71e7ac0 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 23:39:05 +0500 Subject: [PATCH 125/229] fix colors --- .../Assets.xcassets/colorGreen.colorset/Contents.json | 6 +++--- .../Assets.xcassets/colorYellow.colorset/Contents.json | 6 +++--- .../Contents.json | 8 ++++---- novawallet/Common/View/InlineAlertView.swift | 2 +- .../ReferendumVoteSetupViewLayout.swift | 1 + 5 files changed, 12 insertions(+), 11 deletions(-) rename novawallet/Assets.xcassets/{colorYellow12.colorset => colorYellow16.colorset}/Contents.json (66%) diff --git a/novawallet/Assets.xcassets/colorGreen.colorset/Contents.json b/novawallet/Assets.xcassets/colorGreen.colorset/Contents.json index 202ae10a81..303b6db44a 100644 --- a/novawallet/Assets.xcassets/colorGreen.colorset/Contents.json +++ b/novawallet/Assets.xcassets/colorGreen.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0x19", - "green" : "0xFF", - "red" : "0x00" + "blue" : "0x37", + "green" : "0xCF", + "red" : "0x15" } }, "idiom" : "universal" diff --git a/novawallet/Assets.xcassets/colorYellow.colorset/Contents.json b/novawallet/Assets.xcassets/colorYellow.colorset/Contents.json index c6f7ebc14e..a258bc28af 100644 --- a/novawallet/Assets.xcassets/colorYellow.colorset/Contents.json +++ b/novawallet/Assets.xcassets/colorYellow.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0x11", - "green" : "0xE7", - "red" : "0xFF" + "blue" : "0x0A", + "green" : "0xC5", + "red" : "0xEB" } }, "idiom" : "universal" diff --git a/novawallet/Assets.xcassets/colorYellow12.colorset/Contents.json b/novawallet/Assets.xcassets/colorYellow16.colorset/Contents.json similarity index 66% rename from novawallet/Assets.xcassets/colorYellow12.colorset/Contents.json rename to novawallet/Assets.xcassets/colorYellow16.colorset/Contents.json index fb456b3570..8d362450b0 100644 --- a/novawallet/Assets.xcassets/colorYellow12.colorset/Contents.json +++ b/novawallet/Assets.xcassets/colorYellow16.colorset/Contents.json @@ -4,10 +4,10 @@ "color" : { "color-space" : "srgb", "components" : { - "alpha" : "0.120", - "blue" : "0x11", - "green" : "0xE7", - "red" : "0xFF" + "alpha" : "0.160", + "blue" : "0x0A", + "green" : "0xC5", + "red" : "0xEB" } }, "idiom" : "universal" diff --git a/novawallet/Common/View/InlineAlertView.swift b/novawallet/Common/View/InlineAlertView.swift index d12a3de360..7831353f3a 100644 --- a/novawallet/Common/View/InlineAlertView.swift +++ b/novawallet/Common/View/InlineAlertView.swift @@ -50,7 +50,7 @@ final class InlineAlertView: UIView { extension InlineAlertView { static func warning() -> InlineAlertView { let view = InlineAlertView() - view.backgroundView.fillColor = R.color.colorYellow12()! + view.backgroundView.fillColor = R.color.colorYellow16()! view.contentView.imageView.image = R.image.iconWarning() view.contentView.stackView.alignment = .top return view diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift index f80105edb9..77457e7fd3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewLayout.swift @@ -129,6 +129,7 @@ final class ReferendumVoteSetupViewLayout: UIView { let button = TriangularedButton() button.applySecondaryDefaultStyle() button.contentInsets = UIEdgeInsets(top: 6, left: 12, bottom: 6, right: 12) + button.imageWithTitleView?.titleFont = .semiBoldFootnote return button } From 7c278abebb8568521b089a54cd13387f08dd2c1d Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 28 Oct 2022 23:55:41 +0500 Subject: [PATCH 126/229] fix tests --- novawalletIntegrationTests/Gov2OperationFactoryTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift index 39c8cbbcc6..f2e846f6b4 100644 --- a/novawalletIntegrationTests/Gov2OperationFactoryTests.swift +++ b/novawalletIntegrationTests/Gov2OperationFactoryTests.swift @@ -55,7 +55,7 @@ class Gov2OperationFactoryTests: XCTestCase { // when - let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) + let operationFactory = Gov2OperationFactory(requestFactory: requestFactory, operationQueue: operationQueue) let wrapper = operationFactory.fetchAccountVotesWrapper( for: accountId, @@ -83,7 +83,7 @@ class Gov2OperationFactoryTests: XCTestCase { // when - let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) + let operationFactory = Gov2OperationFactory(requestFactory: requestFactory, operationQueue: operationQueue) let wrapper = operationFactory.fetchVotersWrapper( for: ReferendumIdLocal(referendumIndex), @@ -150,7 +150,7 @@ class Gov2OperationFactoryTests: XCTestCase { throw ChainRegistryError.runtimeMetadaUnavailable } - let operationFactory = Gov2OperationFactory(requestFactory: requestFactory) + let operationFactory = Gov2OperationFactory(requestFactory: requestFactory, operationQueue: operationQueue) let wrapper = operationFactory.fetchAllReferendumsWrapper( from: connection, From f3744e6f533d2c2615e45623d0292839c945c5e9 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 29 Oct 2022 17:50:31 +0500 Subject: [PATCH 127/229] add unlock schedule algo implementation --- novawallet.xcodeproj/project.pbxproj | 18 +- .../ConvictionVoting/ConvictionVoting.swift | 4 + .../Model/GovernanceUnlockSchedule.swift | 20 ++ .../Model/ReferendumVotingLocal.swift | 28 ++ .../GovernanceOperationProtocols.swift | 7 + .../Gov2LockStateFactory+UnlockSchedule.swift | 252 ++++++++++++++++++ .../{ => Locks}/Gov2LockStateFactory.swift | 62 ++++- 7 files changed, 379 insertions(+), 12 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift rename novawallet/Modules/Vote/Governance/Operation/{ => Locks}/Gov2LockStateFactory.swift (83%) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 43957b9f42..36faadd553 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -685,6 +685,8 @@ 843461D126E2641500DCE0CD /* SubqueryRewardOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461D026E2641500DCE0CD /* SubqueryRewardOperationFactory.swift */; }; 843461E8290BF14400379936 /* ReferendumsSorting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461E7290BF14400379936 /* ReferendumsSorting.swift */; }; 843461EA290C04C400379936 /* Gov2OperationFactory+Protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */; }; + 843461EC290D0D9400379936 /* GovernanceUnlockSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */; }; + 843461F0290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461EF290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift */; }; 8434C9E425401EF3009E4191 /* TransactionHistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */; }; 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */; }; 8434C9EA2540AE51009E4191 /* ExtrinsicEraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */; }; @@ -3606,6 +3608,8 @@ 843461D026E2641500DCE0CD /* SubqueryRewardOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubqueryRewardOperationFactory.swift; sourceTree = ""; }; 843461E7290BF14400379936 /* ReferendumsSorting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsSorting.swift; sourceTree = ""; }; 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gov2OperationFactory+Protocol.swift"; sourceTree = ""; }; + 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSchedule.swift; sourceTree = ""; }; + 843461EF290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gov2LockStateFactory+UnlockSchedule.swift"; sourceTree = ""; }; 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryItem.swift; sourceTree = ""; }; 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDTransactionHistoryItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicEraTests.swift; sourceTree = ""; }; @@ -7347,6 +7351,15 @@ path = Storage; sourceTree = ""; }; + 843461F1290D370000379936 /* Locks */ = { + isa = PBXGroup; + children = ( + 8427495428FEB92700B2B70B /* Gov2LockStateFactory.swift */, + 843461EF290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift */, + ); + path = Locks; + sourceTree = ""; + }; 84350AD7284604B50031EF24 /* ViewModel */ = { isa = PBXGroup; children = ( @@ -10201,6 +10214,7 @@ 84A1742528ED60610096F943 /* Operation */ = { isa = PBXGroup; children = ( + 843461F1290D370000379936 /* Locks */, 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */, 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */, @@ -10208,7 +10222,6 @@ 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */, 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */, 8425D0EB28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift */, - 8427495428FEB92700B2B70B /* Gov2LockStateFactory.swift */, ); path = Operation; sourceTree = ""; @@ -11481,6 +11494,7 @@ 84880C452902781E00CADB06 /* ReferendumVotingLocal.swift */, 84F1D67029068F810050F4E3 /* GovernanceDApp.swift */, 843461E7290BF14400379936 /* ReferendumsSorting.swift */, + 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */, ); path = Model; sourceTree = ""; @@ -15408,6 +15422,7 @@ F4F65C3826D8B86F002EE838 /* FWXAxisEmptyValueFormatter.swift in Sources */, 8463A6F925E2F82E003B8160 /* CDSingleValue+CoreDataCodable.swift in Sources */, 84ED6BE6286995F400B3C558 /* TransferCrossChainConfirmPresenter.swift in Sources */, + 843461F0290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift in Sources */, 84EBFCE7285E7A7C0006327E /* XcmMessage.swift in Sources */, 8424DB0B26B8466A008C834F /* ValidatorOperationFactoryProtocol.swift in Sources */, 848FFE6625E6742400652AA5 /* EraValidatorService.swift in Sources */, @@ -16852,6 +16867,7 @@ 6003DF3EBB77510EFB70B4E4 /* MessageSheetProtocols.swift in Sources */, 2450083471CD071346371995 /* MessageSheetWireframe.swift in Sources */, 411E74233593A329298C6405 /* MessageSheetPresenter.swift in Sources */, + 843461EC290D0D9400379936 /* GovernanceUnlockSchedule.swift in Sources */, 3FC436AED4098456EDEAF484 /* MessageSheetViewController.swift in Sources */, 842822A4289BCBB200163031 /* SwitchAccount+ParitySignerAddressesWireframe.swift in Sources */, 355476A5AECD2FFE4ED3DE39 /* MessageSheetViewLayout.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index 4a34af4bfb..c65d37cd7f 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -224,6 +224,10 @@ enum ConvictionVoting { @StringCodable var unlockAt: BlockNumber @StringCodable var amount: BigUInt + + var exists: Bool { + unlockAt > 0 || amount > 0 + } } struct CastingVotes: Decodable { diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift new file mode 100644 index 0000000000..5cb0de7100 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift @@ -0,0 +1,20 @@ +import Foundation +import BigInt + +struct GovernanceUnlockSchedule { + enum Action: Equatable, Hashable { + case unvote(track: TrackIdLocal, index: ReferendumIdLocal) + case unlock(track: TrackIdLocal) + } + + struct Item { + let amount: BigUInt + + /// use 0 to mark the lock is available to unlock now + let unlockAt: BlockNumber + + let actions: Set + } + + let items: [Item] +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift index 22d6c51fac..32497d785d 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift @@ -1,4 +1,5 @@ import Foundation +import BigInt struct ReferendumAccountVotingDistribution { let votes: [ReferendumIdLocal: ReferendumAccountVoteLocal] @@ -21,6 +22,33 @@ struct ReferendumAccountVotingDistribution { self.maxVotesPerTrack = maxVotesPerTrack } + func tracksByReferendums() -> [ReferendumIdLocal: TrackIdLocal] { + let initial = [ReferendumIdLocal: TrackIdLocal]() + + return votedTracks.reduce(into: initial) { accum, keyValue in + let trackId = keyValue.key + + for referendumId in keyValue.value { + accum[referendumId] = trackId + } + } + } + + func lockedBalance(for trackId: TrackIdLocal) -> BigUInt { + if let delegating = delegatings[trackId] { + return max(delegating.balance, delegating.prior.amount) + } else { + let maxVotedBalance = (votedTracks[trackId] ?? []).map { referendumId in + votes[referendumId]?.totalBalance ?? 0 + } + .max() ?? 0 + + let priorLockedBalance = priorLocks[trackId]?.amount ?? 0 + + return max(maxVotedBalance, priorLockedBalance) + } + } + func addingVote( _ vote: ReferendumAccountVoteLocal, referendumId: ReferendumIdLocal diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift index 362e6cfb2f..792a7480fa 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceOperationProtocols.swift @@ -38,4 +38,11 @@ protocol GovernanceLockStateFactoryProtocol { runtimeProvider: RuntimeProviderProtocol, blockHash: Data? ) -> CompoundOperationWrapper + + func buildUnlockScheduleWrapper( + for tracksVoting: ReferendumTracksVotingDistribution, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper } diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift new file mode 100644 index 0000000000..a87e32efca --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift @@ -0,0 +1,252 @@ +import Foundation +import RobinHood +import BigInt + +extension Gov2LockStateFactory { + private func createUnlocksFromVotes( + _ votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], + referendums: [ReferendumIdLocal: ReferendumInfo], + tracks: [ReferendumIdLocal: TrackIdLocal], + additionalInfo: AdditionalInfo + ) -> [TrackIdLocal: [GovernanceUnlockSchedule.Item]] { + let initial = [TrackIdLocal: [GovernanceUnlockSchedule.Item]]() + + return votes.reduce(into: initial) { accum, voteKeyValue in + let referendumId = voteKeyValue.key + let vote = voteKeyValue.value + + guard let referendum = referendums[referendumId], let trackId = tracks[referendumId] else { + return + } + + do { + let unlockAt = try estimateVoteLockingPeriod( + for: referendum, + accountVote: vote, + additionalInfo: additionalInfo + ) ?? 0 + + let unvoteAction = GovernanceUnlockSchedule.Action.unvote(track: trackId, index: referendumId) + let unlockAction = GovernanceUnlockSchedule.Action.unlock(track: trackId) + + let unlock = GovernanceUnlockSchedule.Item( + amount: vote.totalBalance, + unlockAt: unlockAt, + actions: [unvoteAction, unlockAction] + ) + + accum[trackId] = (accum[trackId] ?? []) + [unlock] + } catch { + return + } + } + } + + private func createUnlockFromPrior( + _ prior: ConvictionVoting.PriorLock, + trackId: TrackIdLocal + ) -> GovernanceUnlockSchedule.Item { + let priorUnlockAction = GovernanceUnlockSchedule.Action.unlock(track: trackId) + + return GovernanceUnlockSchedule.Item( + amount: prior.amount, + unlockAt: prior.unlockAt, + actions: [priorUnlockAction] + ) + } + + private func extendUnlocksForVotesWithPriors( + _ unlocks: [TrackIdLocal: [GovernanceUnlockSchedule.Item]], + priors: [TrackIdLocal: ConvictionVoting.PriorLock] + ) -> [TrackIdLocal: [GovernanceUnlockSchedule.Item]] { + priors.reduce(into: unlocks) { accum, keyValue in + let trackId = keyValue.key + let priorLock = keyValue.value + + guard priorLock.exists else { + return + } + + /// one can't unlock voted amount if there is a prior in the track that unlocks later + let items: [GovernanceUnlockSchedule.Item] = (unlocks[trackId] ?? []).map { unlock in + if priorLock.unlockAt > unlock.unlockAt { + return GovernanceUnlockSchedule.Item( + amount: unlock.amount, + unlockAt: priorLock.unlockAt, + actions: unlock.actions + ) + } else { + return unlock + } + } + + /// also add a prior unlock separately + let priorUnlock = createUnlockFromPrior(priorLock, trackId: trackId) + + accum[trackId] = items + [priorUnlock] + } + } + + private func extendUnlocksWithDelegatingPriors( + _ unlocks: [TrackIdLocal: [GovernanceUnlockSchedule.Item]], + delegations: [TrackIdLocal: ReferendumDelegatingLocal] + ) -> [TrackIdLocal: [GovernanceUnlockSchedule.Item]] { + delegations.reduce(into: unlocks) { accum, keyValue in + let trackId = keyValue.key + let priorLock = keyValue.value.prior + + guard priorLock.exists else { + return + } + + let priorUnlock = createUnlockFromPrior(priorLock, trackId: trackId) + + /// one can either vote directly or delegate + accum[trackId] = [priorUnlock] + } + } + + private func extendUnlocksWithFreeTracksLocks( + _ tracksVoting: ReferendumTracksVotingDistribution, + unlocks: [TrackIdLocal: [GovernanceUnlockSchedule.Item]] + ) -> [TrackIdLocal: [GovernanceUnlockSchedule.Item]] { + tracksVoting.trackLocks.reduce(into: unlocks) { accum, trackLock in + let trackId = TrackIdLocal(trackLock.trackId) + let trackLockAmount = trackLock.amount + + let neededLockAmount = tracksVoting.votes.lockedBalance(for: trackId) + + if trackLockAmount > neededLockAmount { + let freeAmount = trackLockAmount - neededLockAmount + + let priorUnlockAction = GovernanceUnlockSchedule.Action.unlock(track: trackId) + + let unlock = GovernanceUnlockSchedule.Item( + amount: freeAmount, + unlockAt: 0, + actions: [priorUnlockAction] + ) + + accum[trackId] = (accum[trackId] ?? []) + [unlock] + } + } + } + + private func createVotingUnlocks( + for tracksVoting: ReferendumTracksVotingDistribution, + referendums: [ReferendumIdLocal: ReferendumInfo], + additionalInfo: AdditionalInfo + ) -> [TrackIdLocal: [GovernanceUnlockSchedule.Item]] { + let tracks = tracksVoting.votes.tracksByReferendums() + + let voteUnlocksByTrack = createUnlocksFromVotes( + tracksVoting.votes.votes, + referendums: referendums, + tracks: tracks, + additionalInfo: additionalInfo + ) + + let voteUnlocksWithPriors = extendUnlocksForVotesWithPriors( + voteUnlocksByTrack, + priors: tracksVoting.votes.priorLocks + ) + + let unlocksFromVotesAndDelegatings = extendUnlocksWithDelegatingPriors( + voteUnlocksWithPriors, + delegations: tracksVoting.votes.delegatings + ) + + return extendUnlocksWithFreeTracksLocks(tracksVoting, unlocks: unlocksFromVotesAndDelegatings) + } + + private func flattenUnlocksByBlockNumber( + from unlocks: [TrackIdLocal: [GovernanceUnlockSchedule.Item]] + ) -> [GovernanceUnlockSchedule.Item] { + let initial = [BlockNumber: GovernanceUnlockSchedule.Item]() + + let unlocksByBlockNumber = unlocks.reduce(into: initial) { accum, keyValue in + let trackUnlocks = keyValue.value + + for unlock in trackUnlocks { + if let prevUnlock = accum[unlock.unlockAt] { + accum[unlock.unlockAt] = .init( + amount: max(unlock.amount, prevUnlock.amount), + unlockAt: unlock.unlockAt, + actions: prevUnlock.actions.union(unlock.actions) + ) + } else { + accum[unlock.unlockAt] = unlock + } + } + } + + return Array(unlocksByBlockNumber.values) + } + + private func normalizeUnlocks(_ unlocks: [GovernanceUnlockSchedule.Item]) -> [GovernanceUnlockSchedule.Item] { + var sortedByBlockNumber = unlocks.sorted(by: { $0.unlockAt > $1.unlockAt }) + + var optMaxUnlock: (BigUInt, Int)? + for (index, unlock) in sortedByBlockNumber.enumerated() { + if let maxUnlock = optMaxUnlock { + let maxAmount = maxUnlock.0 + let maxIndex = maxUnlock.1 + + if unlock.amount > maxAmount { + /// new max unlock found + optMaxUnlock = (unlock.amount, index) + + /// only part of the amount can be unlocked + sortedByBlockNumber[index] = .init( + amount: unlock.amount - maxAmount, + unlockAt: unlock.unlockAt, + actions: unlock.actions + ) + } else { + /// this unlock can't happen so move actions to future unlock + let prevUnlock = sortedByBlockNumber[maxIndex] + sortedByBlockNumber[maxIndex] = .init( + amount: prevUnlock.amount, + unlockAt: prevUnlock.unlockAt, + actions: prevUnlock.actions.union(unlock.actions) + ) + + sortedByBlockNumber[index] = .init(amount: 0, unlockAt: unlock.unlockAt, actions: []) + } + + } else { + optMaxUnlock = (unlock.amount, index) + } + } + + return Array(sortedByBlockNumber.reversed().filter { $0.amount > 0 }) + } + + private func createSchedule( + from unlocks: [TrackIdLocal: [GovernanceUnlockSchedule.Item]] + ) -> GovernanceUnlockSchedule { + let flattenedByBlockNumber = flattenUnlocksByBlockNumber(from: unlocks) + let items = normalizeUnlocks(flattenedByBlockNumber) + + return .init(items: items) + } + + func createScheduleOperation( + dependingOn referendumsOperation: BaseOperation<[ReferendumIdLocal: ReferendumInfo]>, + additionalInfoOperation: BaseOperation, + tracksVoting: ReferendumTracksVotingDistribution + ) -> BaseOperation { + ClosureOperation { + let referendums = try referendumsOperation.extractNoCancellableResultData() + let additions = try additionalInfoOperation.extractNoCancellableResultData() + + let unlocks = self.createVotingUnlocks( + for: tracksVoting, + referendums: referendums, + additionalInfo: additions + ) + + return self.createSchedule(from: unlocks) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift similarity index 83% rename from novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift rename to novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift index 8f65b44054..32f86ba75e 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LockStateFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift @@ -32,7 +32,7 @@ final class Gov2LockStateFactory { self.requestFactory = requestFactory } - private func createReferendumsWrapper( + func createReferendumsWrapper( for referendumIds: Set, connection: JSONRPCEngine, codingFactoryOperation: BaseOperation, @@ -61,7 +61,7 @@ final class Gov2LockStateFactory { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: wrapper.allOperations) } - private func createAdditionalInfoWrapper( + func createAdditionalInfoWrapper( dependingOn codingFactoryOperation: BaseOperation ) -> CompoundOperationWrapper { let tracksOperation = StorageConstantOperation<[Referenda.Track]>(path: Referenda.tracks) @@ -118,15 +118,15 @@ final class Gov2LockStateFactory { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: fetchOperations) } - private func estimateVoteLockingPeriod( + func estimateVoteLockingPeriod( for referendumInfo: ReferendumInfo, accountVote: ReferendumAccountVoteLocal, additionalInfo: AdditionalInfo - ) -> BlockNumber? { + ) throws -> BlockNumber? { let conviction = accountVote.convictionValue guard let convictionPeriod = conviction.conviction(for: additionalInfo.voteLockingPeriod) else { - return nil + throw CommonError.dataCorruption } switch referendumInfo { @@ -153,12 +153,14 @@ final class Gov2LockStateFactory { } else { return nil } - case .unknown, .killed, .timedOut, .cancelled: + case .killed, .timedOut, .cancelled: return nil + case .unknown: + throw CommonError.dataCorruption } } - private func calculatePriorLockMax(from trackVotes: ReferendumTracksVotingDistribution) -> BlockNumber? { + func calculatePriorLockMax(from trackVotes: ReferendumTracksVotingDistribution) -> BlockNumber? { let optCastingMax = trackVotes.votes.priorLocks.values .filter { $0.amount > 0 } .map(\.unlockAt) @@ -177,7 +179,7 @@ final class Gov2LockStateFactory { } } - private func calculateMaxLock( + func calculateMaxLock( for referendums: [ReferendumIdLocal: ReferendumInfo], trackVotes: ReferendumTracksVotingDistribution, additions: AdditionalInfo @@ -191,7 +193,7 @@ final class Gov2LockStateFactory { return nil } - return estimateVoteLockingPeriod(for: referendum, accountVote: vote, additionalInfo: additions) + return try? estimateVoteLockingPeriod(for: referendum, accountVote: vote, additionalInfo: additions) }.max() let optPriorMax = calculatePriorLockMax(from: trackVotes) @@ -205,7 +207,7 @@ final class Gov2LockStateFactory { } } - private func createStateDiffOperation( + func createStateDiffOperation( for trackVotes: ReferendumTracksVotingDistribution, newVote: ReferendumNewVote?, referendumsOperation: BaseOperation<[ReferendumIdLocal: ReferendumInfo]>, @@ -245,7 +247,7 @@ final class Gov2LockStateFactory { if newVote.voteAction.amount > 0, let referendum = referendums[newVote.index], - let periodWithNewVote = self.estimateVoteLockingPeriod( + let periodWithNewVote = try? self.estimateVoteLockingPeriod( for: referendum, accountVote: newVote.toAccountVote(), additionalInfo: additions @@ -309,4 +311,42 @@ extension Gov2LockStateFactory: GovernanceLockStateFactoryProtocol { return CompoundOperationWrapper(targetOperation: calculationOperation, dependencies: dependencies) } + + func buildUnlockScheduleWrapper( + for tracksVoting: ReferendumTracksVotingDistribution, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let accountVoting = tracksVoting.votes + let allReferendumIds = Set(accountVoting.votes.keys) + + let referendumsWrapper = createReferendumsWrapper( + for: allReferendumIds, + connection: connection, + codingFactoryOperation: codingFactoryOperation, + blockHash: blockHash + ) + + let additionalInfoWrapper = createAdditionalInfoWrapper(dependingOn: codingFactoryOperation) + + referendumsWrapper.addDependency(operations: [codingFactoryOperation]) + additionalInfoWrapper.addDependency(operations: [codingFactoryOperation]) + + let scheduleOperation = createScheduleOperation( + dependingOn: referendumsWrapper.targetOperation, + additionalInfoOperation: additionalInfoWrapper.targetOperation, + tracksVoting: tracksVoting + ) + + scheduleOperation.addDependency(referendumsWrapper.targetOperation) + scheduleOperation.addDependency(additionalInfoWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + referendumsWrapper.allOperations + + additionalInfoWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: scheduleOperation, dependencies: dependencies) + } } From 1c4f5f073ee47c46fbfb2f1f3791bbf0cb5777b4 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 30 Oct 2022 10:48:39 +0500 Subject: [PATCH 128/229] add helper functions --- .../Model/GovernanceUnlockSchedule.swift | 28 +++++++++++++++++++ .../Gov2LockStateFactory+UnlockSchedule.swift | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift index 5cb0de7100..217e76f2b7 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift @@ -14,7 +14,35 @@ struct GovernanceUnlockSchedule { let unlockAt: BlockNumber let actions: Set + + var isEmpty: Bool { + amount == 0 && actions.isEmpty + } + + static func emptyUnlock(at block: BlockNumber) -> Item { + .init(amount: 0, unlockAt: block, actions: []) + } } let items: [Item] + + func lockedBalance() -> BigUInt { + items.reduce(BigUInt(0)) { $0 + $1.amount } + } + + func availableUnlock(at block: BlockNumber) -> Item { + items + .filter { $0.unlockAt <= block } + .reduce(Item.emptyUnlock(at: block)) { (accum, unlock) in + Item( + amount: accum.amount + unlock.amount, + unlockAt: block, + actions: accum.actions.union(unlock.actions) + ) + } + } + + func remainingLocks(after block: BlockNumber) -> [Item] { + items.filter { $0.unlockAt > block } + } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift index a87e32efca..182e1c07c8 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift @@ -219,7 +219,7 @@ extension Gov2LockStateFactory { } } - return Array(sortedByBlockNumber.reversed().filter { $0.amount > 0 }) + return Array(sortedByBlockNumber.reversed().filter { !$0.isEmpty }) } private func createSchedule( From fa7980bcc4358d67ffd76b50ff2d65b791790ba8 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 30 Oct 2022 11:27:43 +0500 Subject: [PATCH 129/229] refactoring --- novawallet.xcodeproj/project.pbxproj | 12 ++- .../Model/GovernanceUnlockSchedule.swift | 2 +- .../Locks/Gov2LockStateFactory.swift | 89 ++++++------------- ...dule.swift => Gov2UnlocksCalculator.swift} | 78 +++++++++++----- .../Locks/GovernanceUnlocksCalculator.swift | 21 +++++ .../ReferendumVoteConfirmViewFactory.swift | 6 +- .../ReferendumVoteSetupViewFactory.swift | 73 +++++++++------ 7 files changed, 166 insertions(+), 115 deletions(-) rename novawallet/Modules/Vote/Governance/Operation/Locks/{Gov2LockStateFactory+UnlockSchedule.swift => Gov2UnlocksCalculator.swift} (80%) create mode 100644 novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceUnlocksCalculator.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 36faadd553..e393599cbf 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -686,7 +686,8 @@ 843461E8290BF14400379936 /* ReferendumsSorting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461E7290BF14400379936 /* ReferendumsSorting.swift */; }; 843461EA290C04C400379936 /* Gov2OperationFactory+Protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */; }; 843461EC290D0D9400379936 /* GovernanceUnlockSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */; }; - 843461F0290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461EF290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift */; }; + 843461F5290E4A1C00379936 /* GovernanceUnlocksCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */; }; + 843461F7290E4AF500379936 /* Gov2UnlocksCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */; }; 8434C9E425401EF3009E4191 /* TransactionHistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */; }; 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */; }; 8434C9EA2540AE51009E4191 /* ExtrinsicEraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */; }; @@ -3609,7 +3610,8 @@ 843461E7290BF14400379936 /* ReferendumsSorting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsSorting.swift; sourceTree = ""; }; 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gov2OperationFactory+Protocol.swift"; sourceTree = ""; }; 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSchedule.swift; sourceTree = ""; }; - 843461EF290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gov2LockStateFactory+UnlockSchedule.swift"; sourceTree = ""; }; + 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlocksCalculator.swift; sourceTree = ""; }; + 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2UnlocksCalculator.swift; sourceTree = ""; }; 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryItem.swift; sourceTree = ""; }; 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDTransactionHistoryItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicEraTests.swift; sourceTree = ""; }; @@ -7355,7 +7357,8 @@ isa = PBXGroup; children = ( 8427495428FEB92700B2B70B /* Gov2LockStateFactory.swift */, - 843461EF290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift */, + 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */, + 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */, ); path = Locks; sourceTree = ""; @@ -14613,6 +14616,7 @@ 8472979A260B3095009B86D0 /* InitBondSelectValidatorsStartWireframe.swift in Sources */, 84B73AD6279B4E0B0071AE16 /* AssetDetails.swift in Sources */, 88A5317B28B9149600AF18F5 /* UIImage+DrawableIcon.swift in Sources */, + 843461F5290E4A1C00379936 /* GovernanceUnlocksCalculator.swift in Sources */, 84C2063A28D1CA90006D0D52 /* YieldBoostCollatorSelectionFactory.swift in Sources */, 843612BF278FE59D00DC739E /* DAppOperationConfirmInteractor+Proccessing.swift in Sources */, 842BA36F27B64F1000D31EEF /* DAppListViewModelFactory.swift in Sources */, @@ -15422,7 +15426,6 @@ F4F65C3826D8B86F002EE838 /* FWXAxisEmptyValueFormatter.swift in Sources */, 8463A6F925E2F82E003B8160 /* CDSingleValue+CoreDataCodable.swift in Sources */, 84ED6BE6286995F400B3C558 /* TransferCrossChainConfirmPresenter.swift in Sources */, - 843461F0290D1EA500379936 /* Gov2LockStateFactory+UnlockSchedule.swift in Sources */, 84EBFCE7285E7A7C0006327E /* XcmMessage.swift in Sources */, 8424DB0B26B8466A008C834F /* ValidatorOperationFactoryProtocol.swift in Sources */, 848FFE6625E6742400652AA5 /* EraValidatorService.swift in Sources */, @@ -16053,6 +16056,7 @@ 8496ADDE276B123200306B24 /* PolkadotExtentionMessage.swift in Sources */, 84A15489262888CA0050D557 /* IdentityOperationFactory.swift in Sources */, 8473D4212657FFFB00B394B2 /* Crowdloan.swift in Sources */, + 843461F7290E4AF500379936 /* Gov2UnlocksCalculator.swift in Sources */, 849E17E327913220002D1744 /* DAppSearchResult.swift in Sources */, 844CB57626FA064700396E13 /* ChainRegistryError.swift in Sources */, 842A737327DB7F75006EE1EA /* OperationRewardViewModel.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift index 217e76f2b7..f3f3069f88 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift @@ -33,7 +33,7 @@ struct GovernanceUnlockSchedule { func availableUnlock(at block: BlockNumber) -> Item { items .filter { $0.unlockAt <= block } - .reduce(Item.emptyUnlock(at: block)) { (accum, unlock) in + .reduce(Item.emptyUnlock(at: block)) { accum, unlock in Item( amount: accum.amount + unlock.amount, unlockAt: block, diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift index 32f86ba75e..6c1fc278ed 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift @@ -8,8 +8,8 @@ import BigInt * Locked amount diff - maximum amount of tokens locked before vote is applied and after * Locked period diff - period of time needed to unlock all the tokens before vote is applied and after. * - * Locked amount calculation assumes that no unlocks can happen during voting (event if voting for the same referendum). - * So the diff may not decrease. + * Locked amount calculation assumes that no unlocks can happen during + * voting (event if voting for the same referendum). So the diff may not decrease. * * Locked period is calculated first by maximizing estimation for unlock block of votes (only nonzero amount). * And then maximizing result between maximum period for votes and prior locks @@ -20,16 +20,12 @@ import BigInt */ final class Gov2LockStateFactory { - struct AdditionalInfo { - let tracks: [Referenda.TrackId: Referenda.TrackInfo] - let undecidingTimeout: Moment - let voteLockingPeriod: Moment - } - let requestFactory: StorageRequestFactoryProtocol + let unlocksCalculator: GovernanceUnlockCalculatorProtocol - init(requestFactory: StorageRequestFactoryProtocol) { + init(requestFactory: StorageRequestFactoryProtocol, unlocksCalculator: GovernanceUnlockCalculatorProtocol) { self.requestFactory = requestFactory + self.unlocksCalculator = unlocksCalculator } func createReferendumsWrapper( @@ -63,7 +59,7 @@ final class Gov2LockStateFactory { func createAdditionalInfoWrapper( dependingOn codingFactoryOperation: BaseOperation - ) -> CompoundOperationWrapper { + ) -> CompoundOperationWrapper { let tracksOperation = StorageConstantOperation<[Referenda.Track]>(path: Referenda.tracks) tracksOperation.configurationBlock = { @@ -97,7 +93,7 @@ final class Gov2LockStateFactory { let fetchOperations = [tracksOperation, undecidingTimeoutOperation, lockingPeriodOperation] fetchOperations.forEach { $0.addDependency(codingFactoryOperation) } - let mappingOperation = ClosureOperation { + let mappingOperation = ClosureOperation { let tracks = try tracksOperation.extractNoCancellableResultData().reduce( into: [Referenda.TrackId: Referenda.TrackInfo]() ) { $0[$1.trackId] = $1.info } @@ -106,7 +102,7 @@ final class Gov2LockStateFactory { let lockingPeriod = try lockingPeriodOperation.extractNoCancellableResultData() - return AdditionalInfo( + return GovUnlockCalculationInfo( tracks: tracks, undecidingTimeout: undecidingTimeout, voteLockingPeriod: lockingPeriod @@ -118,48 +114,6 @@ final class Gov2LockStateFactory { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: fetchOperations) } - func estimateVoteLockingPeriod( - for referendumInfo: ReferendumInfo, - accountVote: ReferendumAccountVoteLocal, - additionalInfo: AdditionalInfo - ) throws -> BlockNumber? { - let conviction = accountVote.convictionValue - - guard let convictionPeriod = conviction.conviction(for: additionalInfo.voteLockingPeriod) else { - throw CommonError.dataCorruption - } - - switch referendumInfo { - case let .ongoing(ongoingStatus): - guard let track = additionalInfo.tracks[ongoingStatus.track] else { - return nil - } - - if let decidingSince = ongoingStatus.deciding?.since { - return decidingSince + track.decisionPeriod + convictionPeriod - } else { - return ongoingStatus.submitted + additionalInfo.undecidingTimeout + - track.decisionPeriod + convictionPeriod - } - case let .approved(completedStatus): - if accountVote.ayes > 0 { - return completedStatus.since + convictionPeriod - } else { - return nil - } - case let .rejected(completedStatus): - if accountVote.nays > 0 { - return completedStatus.since + convictionPeriod - } else { - return nil - } - case .killed, .timedOut, .cancelled: - return nil - case .unknown: - throw CommonError.dataCorruption - } - } - func calculatePriorLockMax(from trackVotes: ReferendumTracksVotingDistribution) -> BlockNumber? { let optCastingMax = trackVotes.votes.priorLocks.values .filter { $0.amount > 0 } @@ -182,7 +136,7 @@ final class Gov2LockStateFactory { func calculateMaxLock( for referendums: [ReferendumIdLocal: ReferendumInfo], trackVotes: ReferendumTracksVotingDistribution, - additions: AdditionalInfo + additions: GovUnlockCalculationInfo ) -> BlockNumber? { let optVotesMax: Moment? = referendums.compactMap { referendumKeyValue in let referendumIndex = referendumKeyValue.key @@ -193,7 +147,11 @@ final class Gov2LockStateFactory { return nil } - return try? estimateVoteLockingPeriod(for: referendum, accountVote: vote, additionalInfo: additions) + return try? unlocksCalculator.estimateVoteLockingPeriod( + for: referendum, + accountVote: vote, + additionalInfo: additions + ) }.max() let optPriorMax = calculatePriorLockMax(from: trackVotes) @@ -211,7 +169,7 @@ final class Gov2LockStateFactory { for trackVotes: ReferendumTracksVotingDistribution, newVote: ReferendumNewVote?, referendumsOperation: BaseOperation<[ReferendumIdLocal: ReferendumInfo]>, - additionalInfoOperation: BaseOperation + additionalInfoOperation: BaseOperation ) -> BaseOperation { ClosureOperation { let referendums = try referendumsOperation.extractNoCancellableResultData() @@ -247,7 +205,7 @@ final class Gov2LockStateFactory { if newVote.voteAction.amount > 0, let referendum = referendums[newVote.index], - let periodWithNewVote = try? self.estimateVoteLockingPeriod( + let periodWithNewVote = try? self.unlocksCalculator.estimateVoteLockingPeriod( for: referendum, accountVote: newVote.toAccountVote(), additionalInfo: additions @@ -335,11 +293,16 @@ extension Gov2LockStateFactory: GovernanceLockStateFactoryProtocol { referendumsWrapper.addDependency(operations: [codingFactoryOperation]) additionalInfoWrapper.addDependency(operations: [codingFactoryOperation]) - let scheduleOperation = createScheduleOperation( - dependingOn: referendumsWrapper.targetOperation, - additionalInfoOperation: additionalInfoWrapper.targetOperation, - tracksVoting: tracksVoting - ) + let scheduleOperation = ClosureOperation { + let referendums = try referendumsWrapper.targetOperation.extractNoCancellableResultData() + let additions = try additionalInfoWrapper.targetOperation.extractNoCancellableResultData() + + return self.unlocksCalculator.createUnlocksSchedule( + for: tracksVoting, + referendums: referendums, + additionalInfo: additions + ) + } scheduleOperation.addDependency(referendumsWrapper.targetOperation) scheduleOperation.addDependency(additionalInfoWrapper.targetOperation) diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift similarity index 80% rename from novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift rename to novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift index 182e1c07c8..e751a7e584 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory+UnlockSchedule.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift @@ -1,13 +1,12 @@ import Foundation -import RobinHood import BigInt -extension Gov2LockStateFactory { +final class Gov2UnlocksCalculator { private func createUnlocksFromVotes( _ votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], referendums: [ReferendumIdLocal: ReferendumInfo], tracks: [ReferendumIdLocal: TrackIdLocal], - additionalInfo: AdditionalInfo + additionalInfo: GovUnlockCalculationInfo ) -> [TrackIdLocal: [GovernanceUnlockSchedule.Item]] { let initial = [TrackIdLocal: [GovernanceUnlockSchedule.Item]]() @@ -135,7 +134,7 @@ extension Gov2LockStateFactory { private func createVotingUnlocks( for tracksVoting: ReferendumTracksVotingDistribution, referendums: [ReferendumIdLocal: ReferendumInfo], - additionalInfo: AdditionalInfo + additionalInfo: GovUnlockCalculationInfo ) -> [TrackIdLocal: [GovernanceUnlockSchedule.Item]] { let tracks = tracksVoting.votes.tracksByReferendums() @@ -230,23 +229,62 @@ extension Gov2LockStateFactory { return .init(items: items) } +} + +extension Gov2UnlocksCalculator: GovernanceUnlockCalculatorProtocol { + func estimateVoteLockingPeriod( + for referendumInfo: ReferendumInfo, + accountVote: ReferendumAccountVoteLocal, + additionalInfo: GovUnlockCalculationInfo + ) throws -> BlockNumber? { + let conviction = accountVote.convictionValue - func createScheduleOperation( - dependingOn referendumsOperation: BaseOperation<[ReferendumIdLocal: ReferendumInfo]>, - additionalInfoOperation: BaseOperation, - tracksVoting: ReferendumTracksVotingDistribution - ) -> BaseOperation { - ClosureOperation { - let referendums = try referendumsOperation.extractNoCancellableResultData() - let additions = try additionalInfoOperation.extractNoCancellableResultData() - - let unlocks = self.createVotingUnlocks( - for: tracksVoting, - referendums: referendums, - additionalInfo: additions - ) - - return self.createSchedule(from: unlocks) + guard let convictionPeriod = conviction.conviction(for: additionalInfo.voteLockingPeriod) else { + throw CommonError.dataCorruption } + + switch referendumInfo { + case let .ongoing(ongoingStatus): + guard let track = additionalInfo.tracks[ongoingStatus.track] else { + return nil + } + + if let decidingSince = ongoingStatus.deciding?.since { + return decidingSince + track.decisionPeriod + convictionPeriod + } else { + return ongoingStatus.submitted + additionalInfo.undecidingTimeout + + track.decisionPeriod + convictionPeriod + } + case let .approved(completedStatus): + if accountVote.ayes > 0 { + return completedStatus.since + convictionPeriod + } else { + return nil + } + case let .rejected(completedStatus): + if accountVote.nays > 0 { + return completedStatus.since + convictionPeriod + } else { + return nil + } + case .killed, .timedOut, .cancelled: + return nil + case .unknown: + throw CommonError.dataCorruption + } + } + + func createUnlocksSchedule( + for tracksVoting: ReferendumTracksVotingDistribution, + referendums: [ReferendumIdLocal: ReferendumInfo], + additionalInfo: GovUnlockCalculationInfo + ) -> GovernanceUnlockSchedule { + let unlocks = createVotingUnlocks( + for: tracksVoting, + referendums: referendums, + additionalInfo: additionalInfo + ) + + return createSchedule(from: unlocks) } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceUnlocksCalculator.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceUnlocksCalculator.swift new file mode 100644 index 0000000000..f21c886f9f --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceUnlocksCalculator.swift @@ -0,0 +1,21 @@ +import Foundation + +struct GovUnlockCalculationInfo { + let tracks: [Referenda.TrackId: Referenda.TrackInfo] + let undecidingTimeout: Moment + let voteLockingPeriod: Moment +} + +protocol GovernanceUnlockCalculatorProtocol { + func estimateVoteLockingPeriod( + for referendumInfo: ReferendumInfo, + accountVote: ReferendumAccountVoteLocal, + additionalInfo: GovUnlockCalculationInfo + ) throws -> BlockNumber? + + func createUnlocksSchedule( + for tracksVoting: ReferendumTracksVotingDistribution, + referendums: [ReferendumIdLocal: ReferendumInfo], + additionalInfo: GovUnlockCalculationInfo + ) -> GovernanceUnlockSchedule +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift index 39916cecdb..c8498cf99e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -72,6 +72,7 @@ struct ReferendumVoteConfirmViewFactory { return view } + // swiftlint:disable:next function_body_length private static func createInteractor( for state: GovernanceSharedState, referendum: ReferendumIdLocal, @@ -102,7 +103,10 @@ struct ReferendumVoteConfirmViewFactory { operationManager: operationManager ) - let lockStateFactory = Gov2LockStateFactory(requestFactory: requestFactory) + let lockStateFactory = Gov2LockStateFactory( + requestFactory: requestFactory, + unlocksCalculator: Gov2UnlocksCalculator() + ) let extrinsicService = ExtrinsicServiceFactory( runtimeRegistry: runtimeProvider, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index 27b40ccb97..23d8fc9b57 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -10,7 +10,6 @@ struct ReferendumVoteSetupViewFactory { ) -> ReferendumVoteSetupViewProtocol? { guard let chain = state.settings.value, - let assetDisplayInfo = chain.utilityAsset()?.displayInfo(with: chain.icon), let currencyManager = CurrencyManager.shared, let interactor = createInteractor( for: state, @@ -22,7 +21,47 @@ struct ReferendumVoteSetupViewFactory { let wireframe = ReferendumVoteSetupWireframe(state: state) - let localizationManager = LocalizationManager.shared + let dataValidatingFactory = GovernanceValidatorFactory( + presentable: wireframe, + assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), + quantityFormatter: NumberFormatter.quantity.localizableResource() + ) + + guard + let presenter = createPresenter( + from: interactor, + wireframe: wireframe, + dataValidatingFactory: dataValidatingFactory, + referendum: referendum, + chain: chain + ) else { + return nil + } + + let view = ReferendumVoteSetupViewController( + presenter: presenter, + localizationManager: LocalizationManager.shared + ) + + presenter.view = view + dataValidatingFactory.view = view + interactor.presenter = presenter + + return view + } + + private static func createPresenter( + from interactor: ReferendumVoteSetupInteractor, + wireframe: ReferendumVoteSetupWireframeProtocol, + dataValidatingFactory: GovernanceValidatorFactoryProtocol, + referendum: ReferendumIdLocal, + chain: ChainModel + ) -> ReferendumVoteSetupPresenter? { + guard + let assetDisplayInfo = chain.utilityAssetDisplayInfo(), + let currencyManager = CurrencyManager.shared else { + return nil + } let balanceViewModelFactory = BalanceViewModelFactory( targetAssetInfo: assetDisplayInfo, @@ -39,13 +78,7 @@ struct ReferendumVoteSetupViewFactory { let referendumStringsViewModelFactory = ReferendumDisplayStringFactory() - let dataValidatingFactory = GovernanceValidatorFactory( - presentable: wireframe, - assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), - quantityFormatter: NumberFormatter.quantity.localizableResource() - ) - - let presenter = ReferendumVoteSetupPresenter( + return ReferendumVoteSetupPresenter( chain: chain, referendumIndex: referendum, dataValidatingFactory: dataValidatingFactory, @@ -56,20 +89,9 @@ struct ReferendumVoteSetupViewFactory { lockChangeViewModelFactory: lockChangeViewModelFactory, interactor: interactor, wireframe: wireframe, - localizationManager: localizationManager, + localizationManager: LocalizationManager.shared, logger: Logger.shared ) - - let view = ReferendumVoteSetupViewController( - presenter: presenter, - localizationManager: LocalizationManager.shared - ) - - presenter.view = view - dataValidatingFactory.view = view - interactor.presenter = presenter - - return view } private static func createInteractor( @@ -97,12 +119,11 @@ struct ReferendumVoteSetupViewFactory { let operationQueue = OperationManagerFacade.sharedDefaultQueue let operationManager = OperationManager(operationQueue: operationQueue) - let requestFactory = StorageRequestFactory( - remoteFactory: StorageKeyFactory(), - operationManager: operationManager - ) + let storageFactory = StorageKeyFactory() + let requestFactory = StorageRequestFactory(remoteFactory: storageFactory, operationManager: operationManager) - let lockStateFactory = Gov2LockStateFactory(requestFactory: requestFactory) + let calculator = Gov2UnlocksCalculator() + let lockStateFactory = Gov2LockStateFactory(requestFactory: requestFactory, unlocksCalculator: calculator) let extrinsicService = ExtrinsicServiceFactory( runtimeRegistry: runtimeProvider, From 4ab1f8e3543ce71923ae6e5bf5a66ca870b4386a Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 30 Oct 2022 13:23:11 +0500 Subject: [PATCH 130/229] fix tests --- novawallet.xcodeproj/project.pbxproj | 12 ++++ .../ConvictionVoting/ConvictionVoting.swift | 4 ++ .../Governance/GovernanceTestBuilder.swift | 57 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 novawalletTests/Modules/Governance/GovernanceTestBuilder.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index e393599cbf..c03e49b26b 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -688,6 +688,7 @@ 843461EC290D0D9400379936 /* GovernanceUnlockSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */; }; 843461F5290E4A1C00379936 /* GovernanceUnlocksCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */; }; 843461F7290E4AF500379936 /* Gov2UnlocksCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */; }; + 843461FA290E55D100379936 /* GovernanceTestBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F9290E55D100379936 /* GovernanceTestBuilder.swift */; }; 8434C9E425401EF3009E4191 /* TransactionHistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */; }; 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */; }; 8434C9EA2540AE51009E4191 /* ExtrinsicEraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */; }; @@ -3612,6 +3613,7 @@ 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSchedule.swift; sourceTree = ""; }; 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlocksCalculator.swift; sourceTree = ""; }; 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2UnlocksCalculator.swift; sourceTree = ""; }; + 843461F9290E55D100379936 /* GovernanceTestBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceTestBuilder.swift; sourceTree = ""; }; 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryItem.swift; sourceTree = ""; }; 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDTransactionHistoryItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicEraTests.swift; sourceTree = ""; }; @@ -7363,6 +7365,14 @@ path = Locks; sourceTree = ""; }; + 843461F8290E55BE00379936 /* Governance */ = { + isa = PBXGroup; + children = ( + 843461F9290E55D100379936 /* GovernanceTestBuilder.swift */, + ); + path = Governance; + sourceTree = ""; + }; 84350AD7284604B50031EF24 /* ViewModel */ = { isa = PBXGroup; children = ( @@ -10377,6 +10387,7 @@ 84B7C680289BFA78001A3566 /* Modules */ = { isa = PBXGroup; children = ( + 843461F8290E55BE00379936 /* Governance */, 84B7C683289BFA78001A3566 /* Settings */, 84B7C685289BFA78001A3566 /* ParaStkUnstake */, 84B7C686289BFA78001A3566 /* DAppAuthSettings */, @@ -17081,6 +17092,7 @@ 84B7C73B289BFA79001A3566 /* StakingUnbondConfirmTests.swift in Sources */, 842A738E27DEF592006EE1EA /* AssetTransactionGenerator.swift in Sources */, 84CE69ED25667A5600559427 /* ByteLengthEncodingTests.swift in Sources */, + 843461FA290E55D100379936 /* GovernanceTestBuilder.swift in Sources */, 84B7C73D289BFA79001A3566 /* StakingPayoutsConfirmTests.swift in Sources */, 84B7C72E289BFA79001A3566 /* CustomValidatorListTestDataGenerator.swift in Sources */, 84B7C746289BFA79001A3566 /* WalletHistoryFilterTests.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index c65d37cd7f..62cbcc3751 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -228,6 +228,10 @@ enum ConvictionVoting { var exists: Bool { unlockAt > 0 || amount > 0 } + + static var notExisting: PriorLock { + PriorLock(unlockAt: 0, amount: 0) + } } struct CastingVotes: Decodable { diff --git a/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift b/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift new file mode 100644 index 0000000000..afee2f23ba --- /dev/null +++ b/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift @@ -0,0 +1,57 @@ +import Foundation +import BigInt +@testable import novawallet + +final class GovernanceTestBuilder { + struct TrackVoting { + let trackId: TrackIdLocal + let locked: BigUInt + let votes: [ReferendumIdLocal: ReferendumAccountVoteLocal] + let prior: ConvictionVoting.PriorLock + let delegating: ConvictionVoting.Delegating? + + func byChangingLocked(_ locked: BigUInt) -> TrackVoting { + TrackVoting( + trackId: trackId, + locked: locked, + votes: votes, + prior: prior, + delegating: delegating + ) + } + } + + @resultBuilder + class TrackVotingBuilder { + private var voting: TrackVoting + + init(trackId: TrackIdLocal) { + voting = TrackVoting( + trackId: trackId, + locked: 0, + votes: [:], + prior: .notExisting, + delegating: nil + ) + } + + func locked(_ amount: BigUInt) -> TrackVoting { + voting = voting.byChangingLocked(amount) + return voting + } + + static func buildBlock(_ trackId: TrackIdLocal) -> TrackVoting { + TrackVoting( + trackId: trackId, + locked: 0, + votes: [:], + prior: .notExisting, + delegating: nil + ) + } + } + + static func track(@TrackVotingBuilder _ content: () -> TrackVoting) -> TrackVoting { + content() + } +} From 6df78c610e8056ef9d42a2c38fad69c147151a22 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 30 Oct 2022 18:37:50 +0500 Subject: [PATCH 131/229] add tests builder --- .../ConvictionVotingLocks.swift | 5 + .../Governance/GovernanceTestBuilder.swift | 207 ++++++++++++++---- 2 files changed, 175 insertions(+), 37 deletions(-) diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingLocks.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingLocks.swift index 8b855ef6f9..2516c498cf 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingLocks.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingLocks.swift @@ -7,6 +7,11 @@ extension ConvictionVoting { let trackId: Referenda.TrackId let amount: BigUInt + init(trackId: Referenda.TrackId, amount: BigUInt) { + self.trackId = trackId + self.amount = amount + } + public init(from decoder: Decoder) throws { var container = try decoder.unkeyedContainer() diff --git a/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift b/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift index afee2f23ba..c3929a9225 100644 --- a/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift +++ b/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift @@ -2,56 +2,189 @@ import Foundation import BigInt @testable import novawallet -final class GovernanceTestBuilder { - struct TrackVoting { +enum GovernanceTestBuilding { + static func given( + currentBlock: BlockNumber, + @TrackTestBuilding.TrackVotingBuilder _ content: () -> ReferendumTracksVotingDistribution + ) -> GovernanceUnlockSchedule { + let tracksVoting = content() + + let initReferendums = [ReferendumIdLocal: ReferendumInfo]() + let referendums = tracksVoting.votes.tracksByReferendums().keys.reduce(into: initReferendums) { (accum, referendumId) in + let deposit = Referenda.Deposit(who: AccountId.empty, amount: BigUInt(0)) + accum[referendumId] = ReferendumInfo.approved( + .init( + since: currentBlock, + submissionDeposit: deposit, + decisionDeposit: deposit + ) + ) + } + + + + Gov2UnlocksCalculator().createUnlocksSchedule( + for: tracksVoting, + referendums: referendums, + additionalInfo: <#T##GovUnlockCalculationInfo#>) + } +} + +enum TrackTestBuilding { + @resultBuilder + struct TrackVotingBuilder { + static func buildBlock(_ components: Voting...) -> ReferendumTracksVotingDistribution { + let initValue = ReferendumTracksVotingDistribution( + votes: .init(maxVotesPerTrack: 512), + trackLocks: [] + ) + + return components.reduce(initValue) { (accum, voting) in + var accountVoting = accum.votes + + for vote in voting.votes { + accountVoting = accountVoting + .addingReferendum(vote.referendum, track: voting.trackId) + .addingVote( + .standard( + .init( + vote: .init(aye: vote.isAye, conviction: vote.conviction), + balance: vote.balance + ) + ), + referendumId: vote.referendum + ) + } + + if voting.prior.exists { + accountVoting = accountVoting.addingPriorLock(voting.prior, track: voting.trackId) + } + + if let delegating = voting.delegating { + accountVoting = accountVoting.addingDelegating(delegating, trackId: voting.trackId) + } + + let trackLock = ConvictionVoting.ClassLock( + trackId: Referenda.TrackId(voting.trackId), + amount: voting.locked + ) + + return ReferendumTracksVotingDistribution( + votes: accountVoting, + trackLocks: accum.trackLocks + [trackLock] + ) + } + } + } + + struct Voting { let trackId: TrackIdLocal let locked: BigUInt - let votes: [ReferendumIdLocal: ReferendumAccountVoteLocal] + let votes: [Vote] let prior: ConvictionVoting.PriorLock - let delegating: ConvictionVoting.Delegating? - - func byChangingLocked(_ locked: BigUInt) -> TrackVoting { - TrackVoting( - trackId: trackId, - locked: locked, - votes: votes, - prior: prior, - delegating: delegating - ) + let delegating: ReferendumDelegatingLocal? + } + + typealias Locked = BigUInt + + struct Vote { + let referendum: ReferendumIdLocal + let balance: BigUInt + let conviction: ConvictionVoting.Conviction + let isAye: Bool + + init( + referendum: ReferendumIdLocal, + balance: BigUInt, + conviction: ConvictionVoting.Conviction = .locked1x, + isAye: Bool = true + ) { + self.referendum = referendum + self.balance = balance + self.conviction = conviction + self.isAye = isAye } } @resultBuilder - class TrackVotingBuilder { - private var voting: TrackVoting - - init(trackId: TrackIdLocal) { - voting = TrackVoting( - trackId: trackId, - locked: 0, - votes: [:], - prior: .notExisting, - delegating: nil - ) + struct VoteBuilder { + static func buildBlock(_ components: Vote...) -> [Vote] { + Array(components) } + } + + struct VotingParams { + let locked: Locked + let votes: [Vote] + let prior: ConvictionVoting.PriorLock + let delegating: ReferendumDelegatingLocal? - func locked(_ amount: BigUInt) -> TrackVoting { - voting = voting.byChangingLocked(amount) - return voting + static func locked(_ amount: BigUInt) -> VotingParams { + VotingParams(locked: amount, votes: [], prior: .notExisting, delegating: nil) } - static func buildBlock(_ trackId: TrackIdLocal) -> TrackVoting { - TrackVoting( - trackId: trackId, - locked: 0, - votes: [:], - prior: .notExisting, - delegating: nil - ) + static func votes(@VoteBuilder _ content: () -> [Vote]) -> VotingParams { + VotingParams(locked: 0, votes: content(), prior: .notExisting, delegating: nil) + } + + static func prior(amount: BigUInt, unlockAt: BlockNumber) -> VotingParams { + VotingParams(locked: 0, votes: [], prior: .init(unlockAt: unlockAt, amount: amount), delegating: nil) } } - static func track(@TrackVotingBuilder _ content: () -> TrackVoting) -> TrackVoting { - content() + @resultBuilder + class VotingParamsBuilder { + static func buildBlock(_ components: VotingParams...) -> VotingParams { + let initValue = VotingParams(locked: 0, votes: [], prior: .notExisting, delegating: nil) + + return components.reduce(initValue) { (accum, param) in + VotingParams( + locked: accum.locked + param.locked, + votes: accum.votes + param.votes, + prior: param.prior.exists ? param.prior : accum.prior, + delegating: param.delegating != nil ? param.delegating : accum.delegating + ) + } + } + } + + static func track(_ trackId: TrackIdLocal, @VotingParamsBuilder _ builder: () -> VotingParams) -> Voting { + let params = builder() + + return Voting( + trackId: trackId, + locked: params.locked, + votes: params.votes, + prior: params.prior, + delegating: params.delegating + ) + } + + static func tracksVoting( + @TrackVotingBuilder _ builder: () -> ReferendumTracksVotingDistribution + ) -> ReferendumTracksVotingDistribution { + builder() + } +} + +let tracks = TrackTestBuilding.tracksVoting { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.locked(10) + + TrackTestBuilding.VotingParams.prior(amount: 10, unlockAt: 100) + + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 0, balance: 10) + } + } + + TrackTestBuilding.track(1) { + TrackTestBuilding.VotingParams.locked(15) + + TrackTestBuilding.VotingParams.prior(amount: 10, unlockAt: 100) + + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 0, balance: 10) + } } } From 84390ff1f5c6ebdf66f206d36390be0603f769aa Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 31 Oct 2022 02:01:00 +0500 Subject: [PATCH 132/229] add tests --- novawallet.xcodeproj/project.pbxproj | 12 +- .../Model/GovernanceUnlockSchedule.swift | 22 +- .../Governance/Gov2UnlockScheduleTests.swift | 148 +++++++++ .../Governance/GovernanceTestBuilder.swift | 190 ----------- .../GovernanceUnlocksTestBuilding.swift | 308 ++++++++++++++++++ 5 files changed, 481 insertions(+), 199 deletions(-) create mode 100644 novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift delete mode 100644 novawalletTests/Modules/Governance/GovernanceTestBuilder.swift create mode 100644 novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index c03e49b26b..7cefecc548 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -688,7 +688,7 @@ 843461EC290D0D9400379936 /* GovernanceUnlockSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */; }; 843461F5290E4A1C00379936 /* GovernanceUnlocksCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */; }; 843461F7290E4AF500379936 /* Gov2UnlocksCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */; }; - 843461FA290E55D100379936 /* GovernanceTestBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F9290E55D100379936 /* GovernanceTestBuilder.swift */; }; + 843461FA290E55D100379936 /* GovernanceUnlocksTestBuilding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F9290E55D100379936 /* GovernanceUnlocksTestBuilding.swift */; }; 8434C9E425401EF3009E4191 /* TransactionHistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */; }; 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */; }; 8434C9EA2540AE51009E4191 /* ExtrinsicEraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */; }; @@ -1165,6 +1165,7 @@ 8473F4B6282BE488007CC55A /* StakingRelaychainProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8473F4B5282BE488007CC55A /* StakingRelaychainProtocols.swift */; }; 8473F4B8282BFFF8007CC55A /* StakingRelaychainInteractor+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8473F4B7282BFFF8007CC55A /* StakingRelaychainInteractor+Subscription.swift */; }; 8473F4BA282C012B007CC55A /* StakingRelaychainInteractor+InputProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8473F4B9282C012B007CC55A /* StakingRelaychainInteractor+InputProtocol.swift */; }; + 84741ADF290F116B00C98E17 /* Gov2UnlockScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84741ADE290F116B00C98E17 /* Gov2UnlockScheduleTests.swift */; }; 847449512891F3B00042FD80 /* WalletSwitchControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847449502891F3B00042FD80 /* WalletSwitchControl.swift */; }; 84744953289268770042FD80 /* WalletSwitchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84744952289268770042FD80 /* WalletSwitchViewModel.swift */; }; 84744955289284F50042FD80 /* StakingMainViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84744954289284F50042FD80 /* StakingMainViewLayout.swift */; }; @@ -3613,7 +3614,7 @@ 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSchedule.swift; sourceTree = ""; }; 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlocksCalculator.swift; sourceTree = ""; }; 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2UnlocksCalculator.swift; sourceTree = ""; }; - 843461F9290E55D100379936 /* GovernanceTestBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceTestBuilder.swift; sourceTree = ""; }; + 843461F9290E55D100379936 /* GovernanceUnlocksTestBuilding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlocksTestBuilding.swift; sourceTree = ""; }; 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryItem.swift; sourceTree = ""; }; 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDTransactionHistoryItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicEraTests.swift; sourceTree = ""; }; @@ -4096,6 +4097,7 @@ 8473F4B5282BE488007CC55A /* StakingRelaychainProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingRelaychainProtocols.swift; sourceTree = ""; }; 8473F4B7282BFFF8007CC55A /* StakingRelaychainInteractor+Subscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StakingRelaychainInteractor+Subscription.swift"; sourceTree = ""; }; 8473F4B9282C012B007CC55A /* StakingRelaychainInteractor+InputProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StakingRelaychainInteractor+InputProtocol.swift"; sourceTree = ""; }; + 84741ADE290F116B00C98E17 /* Gov2UnlockScheduleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2UnlockScheduleTests.swift; sourceTree = ""; }; 847449502891F3B00042FD80 /* WalletSwitchControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSwitchControl.swift; sourceTree = ""; }; 84744952289268770042FD80 /* WalletSwitchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSwitchViewModel.swift; sourceTree = ""; }; 84744954289284F50042FD80 /* StakingMainViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingMainViewLayout.swift; sourceTree = ""; }; @@ -7368,7 +7370,8 @@ 843461F8290E55BE00379936 /* Governance */ = { isa = PBXGroup; children = ( - 843461F9290E55D100379936 /* GovernanceTestBuilder.swift */, + 843461F9290E55D100379936 /* GovernanceUnlocksTestBuilding.swift */, + 84741ADE290F116B00C98E17 /* Gov2UnlockScheduleTests.swift */, ); path = Governance; sourceTree = ""; @@ -17092,7 +17095,7 @@ 84B7C73B289BFA79001A3566 /* StakingUnbondConfirmTests.swift in Sources */, 842A738E27DEF592006EE1EA /* AssetTransactionGenerator.swift in Sources */, 84CE69ED25667A5600559427 /* ByteLengthEncodingTests.swift in Sources */, - 843461FA290E55D100379936 /* GovernanceTestBuilder.swift in Sources */, + 843461FA290E55D100379936 /* GovernanceUnlocksTestBuilding.swift in Sources */, 84B7C73D289BFA79001A3566 /* StakingPayoutsConfirmTests.swift in Sources */, 84B7C72E289BFA79001A3566 /* CustomValidatorListTestDataGenerator.swift in Sources */, 84B7C746289BFA79001A3566 /* WalletHistoryFilterTests.swift in Sources */, @@ -17125,6 +17128,7 @@ 84CE9AE926CAA83100B4EF62 /* RuntimeProviderTests.swift in Sources */, 849ECD3526DE70B900F542A3 /* SingleToMultiassetUserMigrationTests.swift in Sources */, 8467FD0D24E5E585005D486C /* KeystoreImportTests.swift in Sources */, + 84741ADF290F116B00C98E17 /* Gov2UnlockScheduleTests.swift in Sources */, 8476CA0B25EFB17A003EEAE1 /* RewardCalculatorServiceStub.swift in Sources */, 84F81318265B9E990043FA1D /* CrowdloansOperationFactoryStub.swift in Sources */, 847F2D5727AB08D200AFD476 /* GradientColorFactoryTests.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift index f3f3069f88..027cf6c7cd 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift @@ -7,7 +7,7 @@ struct GovernanceUnlockSchedule { case unlock(track: TrackIdLocal) } - struct Item { + struct Item: Equatable { let amount: BigUInt /// use 0 to mark the lock is available to unlock now @@ -24,19 +24,31 @@ struct GovernanceUnlockSchedule { } } + struct Claimable: Equatable { + let amount: BigUInt + let actions: Set + + var isEmpty: Bool { + amount == 0 && actions.isEmpty + } + + static func empty() -> Claimable { + Claimable(amount: 0, actions: []) + } + } + let items: [Item] func lockedBalance() -> BigUInt { items.reduce(BigUInt(0)) { $0 + $1.amount } } - func availableUnlock(at block: BlockNumber) -> Item { + func availableUnlock(at block: BlockNumber) -> Claimable { items .filter { $0.unlockAt <= block } - .reduce(Item.emptyUnlock(at: block)) { accum, unlock in - Item( + .reduce(Claimable.empty()) { accum, unlock in + .init( amount: accum.amount + unlock.amount, - unlockAt: block, actions: accum.actions.union(unlock.actions) ) } diff --git a/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift b/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift new file mode 100644 index 0000000000..adff53b4de --- /dev/null +++ b/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift @@ -0,0 +1,148 @@ +import XCTest +@testable import novawallet + +class Gov2UnlockScheduleTests: XCTestCase { + + func testShouldHandleEmpty() { + GovernanceUnlocksTestBuilding.run(atBlock: 0) { + GovernanceUnlocksTestBuilding.given {} + GovernanceUnlocksTestBuilding.expect {} + } + } + + func testShouldHandleSingleClaimable() { + GovernanceUnlocksTestBuilding.run(atBlock: 1000) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 0, balance: 1, unlockAt: 1000) + } + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 1) { + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 0) + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + } + } + } + + func testShouldHandleBothPassedAndNotPriors() { + GovernanceUnlocksTestBuilding.run(atBlock: 1000) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.prior(amount: 2, unlockAt: 1000) + } + + TrackTestBuilding.track(1) { + TrackTestBuilding.VotingParams.prior(amount: 1, unlockAt: 1100) + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 1) { + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + + UnlockScheduleTestBuilding.ScheduleResult.remainingItems { + UnlockScheduleTestBuilding.unlock(amount: 1, atBlock: 1100) { + GovernanceUnlockSchedule.Action.unlock(track: 1) + } + } + } + } + } + + func testShouldExtendVotesWithPrior() { + GovernanceUnlocksTestBuilding.run(atBlock: 1000) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.prior(amount: 1, unlockAt: 1100) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 1, balance: 2, unlockAt: 1000) + } + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.remainingItems { + UnlockScheduleTestBuilding.unlock(amount: 2, atBlock: 1100) { + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 1) + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + } + } + } + } + + func testShouldTakeMaxBetweenTwoLocksWithSameTime() { + GovernanceUnlocksTestBuilding.run(atBlock: 1000) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 0, balance: 8, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 1, balance: 2, unlockAt: 1000) + } + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 8) { + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 0) + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 1) + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + } + } + } + + func testShouldHandleRegiggedPrior() { + GovernanceUnlocksTestBuilding.run(atBlock: 1200) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.prior(amount: 1, unlockAt: 1100) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 1, balance: 2, unlockAt: 1000) + } + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 2) { + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 1) + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + } + } + } + + func testShouldFoldSeveralClaimableToOne() { + GovernanceUnlocksTestBuilding.run(atBlock: 1100) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.locked(0) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 0, balance: 1, unlockAt: 1100) + } + } + TrackTestBuilding.track(1) { + TrackTestBuilding.VotingParams.locked(0) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 1, balance: 2, unlockAt: 1000) + } + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 2) { + GovernanceUnlockSchedule.Action.unvote(track: 1, index: 1) + GovernanceUnlockSchedule.Action.unlock(track: 1) + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 0) + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + } + } + } +} diff --git a/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift b/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift deleted file mode 100644 index c3929a9225..0000000000 --- a/novawalletTests/Modules/Governance/GovernanceTestBuilder.swift +++ /dev/null @@ -1,190 +0,0 @@ -import Foundation -import BigInt -@testable import novawallet - -enum GovernanceTestBuilding { - static func given( - currentBlock: BlockNumber, - @TrackTestBuilding.TrackVotingBuilder _ content: () -> ReferendumTracksVotingDistribution - ) -> GovernanceUnlockSchedule { - let tracksVoting = content() - - let initReferendums = [ReferendumIdLocal: ReferendumInfo]() - let referendums = tracksVoting.votes.tracksByReferendums().keys.reduce(into: initReferendums) { (accum, referendumId) in - let deposit = Referenda.Deposit(who: AccountId.empty, amount: BigUInt(0)) - accum[referendumId] = ReferendumInfo.approved( - .init( - since: currentBlock, - submissionDeposit: deposit, - decisionDeposit: deposit - ) - ) - } - - - - Gov2UnlocksCalculator().createUnlocksSchedule( - for: tracksVoting, - referendums: referendums, - additionalInfo: <#T##GovUnlockCalculationInfo#>) - } -} - -enum TrackTestBuilding { - @resultBuilder - struct TrackVotingBuilder { - static func buildBlock(_ components: Voting...) -> ReferendumTracksVotingDistribution { - let initValue = ReferendumTracksVotingDistribution( - votes: .init(maxVotesPerTrack: 512), - trackLocks: [] - ) - - return components.reduce(initValue) { (accum, voting) in - var accountVoting = accum.votes - - for vote in voting.votes { - accountVoting = accountVoting - .addingReferendum(vote.referendum, track: voting.trackId) - .addingVote( - .standard( - .init( - vote: .init(aye: vote.isAye, conviction: vote.conviction), - balance: vote.balance - ) - ), - referendumId: vote.referendum - ) - } - - if voting.prior.exists { - accountVoting = accountVoting.addingPriorLock(voting.prior, track: voting.trackId) - } - - if let delegating = voting.delegating { - accountVoting = accountVoting.addingDelegating(delegating, trackId: voting.trackId) - } - - let trackLock = ConvictionVoting.ClassLock( - trackId: Referenda.TrackId(voting.trackId), - amount: voting.locked - ) - - return ReferendumTracksVotingDistribution( - votes: accountVoting, - trackLocks: accum.trackLocks + [trackLock] - ) - } - } - } - - struct Voting { - let trackId: TrackIdLocal - let locked: BigUInt - let votes: [Vote] - let prior: ConvictionVoting.PriorLock - let delegating: ReferendumDelegatingLocal? - } - - typealias Locked = BigUInt - - struct Vote { - let referendum: ReferendumIdLocal - let balance: BigUInt - let conviction: ConvictionVoting.Conviction - let isAye: Bool - - init( - referendum: ReferendumIdLocal, - balance: BigUInt, - conviction: ConvictionVoting.Conviction = .locked1x, - isAye: Bool = true - ) { - self.referendum = referendum - self.balance = balance - self.conviction = conviction - self.isAye = isAye - } - } - - @resultBuilder - struct VoteBuilder { - static func buildBlock(_ components: Vote...) -> [Vote] { - Array(components) - } - } - - struct VotingParams { - let locked: Locked - let votes: [Vote] - let prior: ConvictionVoting.PriorLock - let delegating: ReferendumDelegatingLocal? - - static func locked(_ amount: BigUInt) -> VotingParams { - VotingParams(locked: amount, votes: [], prior: .notExisting, delegating: nil) - } - - static func votes(@VoteBuilder _ content: () -> [Vote]) -> VotingParams { - VotingParams(locked: 0, votes: content(), prior: .notExisting, delegating: nil) - } - - static func prior(amount: BigUInt, unlockAt: BlockNumber) -> VotingParams { - VotingParams(locked: 0, votes: [], prior: .init(unlockAt: unlockAt, amount: amount), delegating: nil) - } - } - - @resultBuilder - class VotingParamsBuilder { - static func buildBlock(_ components: VotingParams...) -> VotingParams { - let initValue = VotingParams(locked: 0, votes: [], prior: .notExisting, delegating: nil) - - return components.reduce(initValue) { (accum, param) in - VotingParams( - locked: accum.locked + param.locked, - votes: accum.votes + param.votes, - prior: param.prior.exists ? param.prior : accum.prior, - delegating: param.delegating != nil ? param.delegating : accum.delegating - ) - } - } - } - - static func track(_ trackId: TrackIdLocal, @VotingParamsBuilder _ builder: () -> VotingParams) -> Voting { - let params = builder() - - return Voting( - trackId: trackId, - locked: params.locked, - votes: params.votes, - prior: params.prior, - delegating: params.delegating - ) - } - - static func tracksVoting( - @TrackVotingBuilder _ builder: () -> ReferendumTracksVotingDistribution - ) -> ReferendumTracksVotingDistribution { - builder() - } -} - -let tracks = TrackTestBuilding.tracksVoting { - TrackTestBuilding.track(0) { - TrackTestBuilding.VotingParams.locked(10) - - TrackTestBuilding.VotingParams.prior(amount: 10, unlockAt: 100) - - TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 0, balance: 10) - } - } - - TrackTestBuilding.track(1) { - TrackTestBuilding.VotingParams.locked(15) - - TrackTestBuilding.VotingParams.prior(amount: 10, unlockAt: 100) - - TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 0, balance: 10) - } - } -} diff --git a/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift b/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift new file mode 100644 index 0000000000..18d3eaece0 --- /dev/null +++ b/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift @@ -0,0 +1,308 @@ +import XCTest +@testable import novawallet +import BigInt + +enum GovernanceUnlocksTestBuilding { + struct Test { + let givenSchedule: GovernanceUnlockSchedule? + let expectSchedule: UnlockScheduleTestBuilding.ScheduleResult? + } + + @resultBuilder + struct TestBuilder { + static func buildBlock(_ givenSchedule: GovernanceUnlockSchedule) -> Test { + .init(givenSchedule: givenSchedule, expectSchedule: nil) + } + + static func buildBlock(_ expectSchedule: UnlockScheduleTestBuilding.ScheduleResult) -> Test { + .init(givenSchedule: nil, expectSchedule: expectSchedule) + } + + static func buildBlock(_ components: Test...) -> Test { + let initTest = Test(givenSchedule: nil, expectSchedule: nil) + + return components.reduce(initTest) { (accum, test) in + let given = test.givenSchedule ?? accum.givenSchedule + let expect = test.expectSchedule ?? accum.expectSchedule + + return .init(givenSchedule: given, expectSchedule: expect) + } + } + } + + static func run(atBlock block: BlockNumber, @TestBuilder _ builder: () -> Test) { + let test = builder() + + guard let schedule = test.givenSchedule else { + XCTFail("Give schedule is not provided") + return + } + + guard let expect = test.expectSchedule else { + XCTFail("Expected result is not provided") + return + } + + XCTAssertEqual(schedule.availableUnlock(at: block), expect.available) + XCTAssertEqual(schedule.remainingLocks(after: block), expect.remaining) + } + + static func given( + @TrackTestBuilding.TrackVotingBuilder _ content: () -> TrackTestBuilding.VotingWithReferendumUnlock + ) -> Test { + let compoundVoting = content() + + let tracksVoting = compoundVoting.votingDistribution + let refendumsUnlock = compoundVoting.referendumsUnlock + + let initReferendums = [ReferendumIdLocal: ReferendumInfo]() + let referendums = tracksVoting.votes.tracksByReferendums().keys.reduce(into: initReferendums) { (accum, referendumId) in + let deposit = Referenda.Deposit(who: AccountId.zeroAccountId(of: 32), amount: BigUInt(0)) + accum[referendumId] = ReferendumInfo.approved( + .init( + since: refendumsUnlock[referendumId] ?? 0, + submissionDeposit: deposit, + decisionDeposit: deposit + ) + ) + } + + let additions = GovUnlockCalculationInfo( + tracks: [:], + undecidingTimeout: 0, + voteLockingPeriod: 0 + ) + + let schedule = Gov2UnlocksCalculator().createUnlocksSchedule( + for: tracksVoting, + referendums: referendums, + additionalInfo: additions + ) + + return .init(givenSchedule: schedule, expectSchedule: nil) + } + + static func expect( + @UnlockScheduleTestBuilding.ScheduleResultBuilder _ builder: () -> UnlockScheduleTestBuilding.ScheduleResult + ) -> Test { + let result = builder() + + return .init(givenSchedule: nil, expectSchedule: result) + } +} + +enum UnlockScheduleTestBuilding { + @resultBuilder + struct ClaimActionBuilder { + static func buildBlock(_ components: GovernanceUnlockSchedule.Action...) -> Set { + Set(components) + } + } + + @resultBuilder + struct ItemBuilder { + static func buildBlock(_ components: GovernanceUnlockSchedule.Item...) -> [GovernanceUnlockSchedule.Item] { + Array(components) + } + } + + struct ScheduleResult { + let available: GovernanceUnlockSchedule.Claimable + let remaining: [GovernanceUnlockSchedule.Item] + + static func availableItem( + amount: BigUInt, + @ClaimActionBuilder _ actionsBlock: () -> Set + ) -> ScheduleResult { + return .init( + available: + .init( + amount: amount, + actions: actionsBlock() + ), + remaining: [] + ) + } + + static func remainingItems(@ItemBuilder _ block: () -> [GovernanceUnlockSchedule.Item]) -> ScheduleResult { + .init(available: .empty(), remaining: block()) + } + } + + @resultBuilder + struct ScheduleResultBuilder { + static func buildBlock(_ components: ScheduleResult...) -> ScheduleResult { + let initResult = ScheduleResult(available: .empty(), remaining: []) + + return components.reduce(initResult) { (accum, schedule) in + let available = !schedule.available.isEmpty ? schedule.available : accum.available + let remaining = accum.remaining + schedule.remaining + + return .init(available: available, remaining: remaining) + } + } + } + + static func unlock( + amount: BigUInt, + atBlock: BlockNumber, + @ClaimActionBuilder _ actionsBlock: () -> Set + ) -> GovernanceUnlockSchedule.Item { + let actions = actionsBlock() + + return .init(amount: amount, unlockAt: atBlock, actions: actions) + } +} + +enum TrackTestBuilding { + struct VotingWithReferendumUnlock { + let votingDistribution: ReferendumTracksVotingDistribution + let referendumsUnlock: [ReferendumIdLocal: BlockNumber] + } + + @resultBuilder + struct TrackVotingBuilder { + static func buildBlock(_ components: Voting...) -> VotingWithReferendumUnlock { + let initValue = ReferendumTracksVotingDistribution( + votes: .init(maxVotesPerTrack: 512), + trackLocks: [] + ) + + let votingDistribution = components.reduce(initValue) { (accum, voting) in + var accountVoting = accum.votes + + for vote in voting.votes { + accountVoting = accountVoting + .addingReferendum(vote.referendum, track: voting.trackId) + .addingVote( + .standard( + .init( + vote: .init(aye: vote.isAye, conviction: vote.conviction), + balance: vote.balance + ) + ), + referendumId: vote.referendum + ) + } + + if voting.prior.exists { + accountVoting = accountVoting.addingPriorLock(voting.prior, track: voting.trackId) + } + + if let delegating = voting.delegating { + accountVoting = accountVoting.addingDelegating(delegating, trackId: voting.trackId) + } + + let trackLock = ConvictionVoting.ClassLock( + trackId: Referenda.TrackId(voting.trackId), + amount: voting.locked + ) + + return ReferendumTracksVotingDistribution( + votes: accountVoting, + trackLocks: accum.trackLocks + [trackLock] + ) + } + + let referendumsUnlock = components.reduce(into: [ReferendumIdLocal: BlockNumber]()) { (accum, voting) in + for vote in voting.votes { + accum[vote.referendum] = vote.unlockAt + } + } + + return .init(votingDistribution: votingDistribution, referendumsUnlock: referendumsUnlock) + } + } + + struct Voting { + let trackId: TrackIdLocal + let locked: BigUInt + let votes: [Vote] + let prior: ConvictionVoting.PriorLock + let delegating: ReferendumDelegatingLocal? + } + + typealias Locked = BigUInt + + struct Vote { + let referendum: ReferendumIdLocal + let balance: BigUInt + let conviction: ConvictionVoting.Conviction + let unlockAt: BlockNumber + let isAye: Bool + + init( + referendum: ReferendumIdLocal, + balance: BigUInt, + unlockAt: BlockNumber, + conviction: ConvictionVoting.Conviction = .locked1x, + isAye: Bool = true + ) { + self.referendum = referendum + self.balance = balance + self.unlockAt = unlockAt + self.conviction = conviction + self.isAye = isAye + } + } + + @resultBuilder + struct VoteBuilder { + static func buildBlock(_ components: Vote...) -> [Vote] { + Array(components) + } + } + + struct VotingParams { + let locked: Locked + let votes: [Vote] + let prior: ConvictionVoting.PriorLock + let delegating: ReferendumDelegatingLocal? + + static func locked(_ amount: BigUInt) -> VotingParams { + VotingParams(locked: amount, votes: [], prior: .notExisting, delegating: nil) + } + + static func votes(@VoteBuilder _ content: () -> [Vote]) -> VotingParams { + VotingParams(locked: 0, votes: content(), prior: .notExisting, delegating: nil) + } + + static func prior(amount: BigUInt, unlockAt: BlockNumber) -> VotingParams { + VotingParams(locked: 0, votes: [], prior: .init(unlockAt: unlockAt, amount: amount), delegating: nil) + } + } + + @resultBuilder + class VotingParamsBuilder { + static func buildBlock(_ components: VotingParams...) -> VotingParams { + let initValue = VotingParams(locked: 0, votes: [], prior: .notExisting, delegating: nil) + + return components.reduce(initValue) { (accum, param) in + VotingParams( + locked: accum.locked + param.locked, + votes: accum.votes + param.votes, + prior: param.prior.exists ? param.prior : accum.prior, + delegating: param.delegating != nil ? param.delegating : accum.delegating + ) + } + } + } + + static func track(_ trackId: TrackIdLocal, @VotingParamsBuilder _ builder: () -> VotingParams) -> Voting { + let params = builder() + + return Voting( + trackId: trackId, + locked: params.locked, + votes: params.votes, + prior: params.prior, + delegating: params.delegating + ) + } + + static func tracksVoting( + @TrackVotingBuilder _ builder: () -> VotingWithReferendumUnlock + ) -> VotingWithReferendumUnlock { + builder() + } +} From 7bd5904cbf31cac3dc28963e8584f58cc03a3acf Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 31 Oct 2022 11:18:23 +0500 Subject: [PATCH 133/229] unlock schedule algo tests --- .../Locks/Gov2UnlocksCalculator.swift | 50 ++++- .../Governance/Gov2UnlockScheduleTests.swift | 202 ++++++++++++++++++ 2 files changed, 249 insertions(+), 3 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift index e751a7e584..2589d2e33a 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift @@ -1,6 +1,52 @@ import Foundation import BigInt +/** + * Given the information about Voting (priors + active votes), statuses of referenda and TrackLocks + * Constructs the estimated claiming schedule. + * The schedule is exact when all involved referenda are completed. Only ongoing referenda' end time is estimateted + * + * The claiming schedule shows how much tokens will be unlocked and when. + * Schedule may consist of zero or one [ClaimSchedule.UnlockChunk.Claimable] chunk + * and zero or more [ClaimSchedule.UnlockChunk.Pending] chunks. + * + * [ClaimSchedule.UnlockChunk.Pending] chunks also provides a set of [ClaimSchedule.ClaimAction] actions + * needed to claim whole chunk. + * + * The algorithm itself consists of several parts + * + * 1. Determine individual unlocks + * This step is based on prior [Voting.Casting.prior] and [AccountVote.Standard] standard votes + * a. Each non-zero prior has a single individual unlock + * b. Each non-zero vote has a single individual unlock. + * However, unlock time for votes is at least unlock time of corresponding prior. + * c. Find a gap between [voting] and [trackLocks], which indicates an extra claimable amount + * To provide additive effect of gap, we add total voting lock on top of it: + if [voting] has some pending locks - they gonna delay their amount but always leaving trackGap untouched & claimable + On the other hand, if other tracks have locks bigger than [voting]'s total lock, + trackGap will be partially or full delayed by them + * + * During this step we also determine the list of [ClaimAffect], + * which later gets translated to [ClaimSchedule.ClaimAction]. + * + * 2. Combine all locks with the same unlock time into single lock + * a. Result's amount is the maximum between combined locks + * b. Result's affects is a concatenation of all affects from combined locks + * + * 3. Construct preliminary unlock schedule based on the following algorithm + * a. Sort pairs from step (2) by descending [ClaimableLock.claimAt] order + * b. For each item in the sorted list, find the difference between the biggest currently processed lock and item's amount + * c. Since we start from the most far locks in the future, finding a positive difference means that + * this difference is actually an entry in desired unlock schedule. Negative difference means that this unlock is + * completely covered by future's unlock with bigger amount. Thus, we should discard it from the schedule and move its affects + * to the currently known maximum lock in order to not to loose its actions when unlocking maximum lock. + * + * 4. Check which if unlocks are claimable and which are not by constructing [ClaimSchedule.UnlockChunk] based on [currentBlockNumber] + * 5. Fold all [ClaimSchedule.UnlockChunk] into single chunk. + * 6. If gap exists, then we should add it to claimable chunk. We should also check if we should perform extra [ClaimSchedule.ClaimAction.Unlock] + * for each track that is included in the gap. We do that by finding by checking which [ClaimSchedule.ClaimAction.Unlock] unlocks are already present + * in claimable chunk's actions in order to not to do them twice. + */ final class Gov2UnlocksCalculator { private func createUnlocksFromVotes( _ votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], @@ -116,12 +162,10 @@ final class Gov2UnlocksCalculator { let neededLockAmount = tracksVoting.votes.lockedBalance(for: trackId) if trackLockAmount > neededLockAmount { - let freeAmount = trackLockAmount - neededLockAmount - let priorUnlockAction = GovernanceUnlockSchedule.Action.unlock(track: trackId) let unlock = GovernanceUnlockSchedule.Item( - amount: freeAmount, + amount: trackLockAmount, unlockAt: 0, actions: [priorUnlockAction] ) diff --git a/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift b/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift index adff53b4de..a4c704684d 100644 --- a/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift +++ b/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift @@ -145,4 +145,206 @@ class Gov2UnlockScheduleTests: XCTestCase { } } } + + func testShouldIncludeShadowedAction() { + GovernanceUnlocksTestBuilding.run(atBlock: 1200) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(1) { + TrackTestBuilding.VotingParams.locked(0) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 1, balance: 1, unlockAt: 1000) + } + } + TrackTestBuilding.track(2) { + TrackTestBuilding.VotingParams.locked(0) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 2, balance: 2, unlockAt: 1100) + } + } + TrackTestBuilding.track(3) { + TrackTestBuilding.VotingParams.locked(0) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 3, balance: 1, unlockAt: 1200) + } + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 2) { + GovernanceUnlockSchedule.Action.unvote(track: 2, index: 2) + GovernanceUnlockSchedule.Action.unlock(track: 2) + GovernanceUnlockSchedule.Action.unvote(track: 1, index: 1) + GovernanceUnlockSchedule.Action.unlock(track: 1) + GovernanceUnlockSchedule.Action.unvote(track: 3, index: 3) + GovernanceUnlockSchedule.Action.unlock(track: 3) + } + } + } + } + + func testShouldTakeGapIntoAccount() { + GovernanceUnlocksTestBuilding.run(atBlock: 1000) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.locked(10) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 0, balance: 2, unlockAt: 1000) + } + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 10) { + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 0) + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + } + } + } + + func testGapShouldBeLimitedWithOtherLocks() { + GovernanceUnlocksTestBuilding.run(atBlock: 1000) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.locked(10) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 0, balance: 1, unlockAt: 1000) + } + } + + TrackTestBuilding.track(1) { + TrackTestBuilding.VotingParams.prior(amount: 10, unlockAt: 1000) + } + + TrackTestBuilding.track(2) { + TrackTestBuilding.VotingParams.prior(amount: 1, unlockAt: 1100) + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 9) { + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 0) + GovernanceUnlockSchedule.Action.unlock(track: 0) + GovernanceUnlockSchedule.Action.unlock(track: 1) + } + + UnlockScheduleTestBuilding.ScheduleResult.remainingItems { + UnlockScheduleTestBuilding.unlock(amount: 1, atBlock: 1100) { + GovernanceUnlockSchedule.Action.unlock(track: 2) + } + } + } + } + } + + func testGapClaimShouldBeDelayed() { + GovernanceUnlocksTestBuilding.run(atBlock: 1000) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.locked(10) + } + + TrackTestBuilding.track(1) { + TrackTestBuilding.VotingParams.prior(amount: 10, unlockAt: 1100) + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.remainingItems { + UnlockScheduleTestBuilding.unlock(amount: 10, atBlock: 1100) { + GovernanceUnlockSchedule.Action.unlock(track: 0) + GovernanceUnlockSchedule.Action.unlock(track: 1) + } + } + } + } + } + + func testShouldNotDuplicateUnlockCommandWithBothPriorAndGapPresent() { + GovernanceUnlocksTestBuilding.run(atBlock: 1100) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.locked(10) + TrackTestBuilding.VotingParams.prior(amount: 5, unlockAt: 1050) + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 10) { + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + } + } + } + + func testPendingShouldBeSortedByRemainingTime() { + GovernanceUnlocksTestBuilding.run(atBlock: 1000) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(0) { + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 0, balance: 3, unlockAt: 1100) + TrackTestBuilding.Vote(referendum: 2, balance: 2, unlockAt: 1200) + TrackTestBuilding.Vote(referendum: 1, balance: 1, unlockAt: 1300) + } + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.remainingItems { + UnlockScheduleTestBuilding.unlock(amount: 1, atBlock: 1100) { + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 0) + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + + UnlockScheduleTestBuilding.unlock(amount: 1, atBlock: 1200) { + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 2) + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + + UnlockScheduleTestBuilding.unlock(amount: 1, atBlock: 1300) { + GovernanceUnlockSchedule.Action.unvote(track: 0, index: 1) + GovernanceUnlockSchedule.Action.unlock(track: 0) + } + } + } + } + } + + func testGapShouldNotBeCoveredByItsTrackLocks() { + GovernanceUnlocksTestBuilding.run(atBlock: 1000) { + GovernanceUnlocksTestBuilding.given { + TrackTestBuilding.track(20) { + TrackTestBuilding.VotingParams.locked(1) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 13, balance: 1, unlockAt: 2000) + } + } + + TrackTestBuilding.track(21) { + TrackTestBuilding.VotingParams.locked(101) + TrackTestBuilding.VotingParams.votes { + TrackTestBuilding.Vote(referendum: 5, balance: 10, unlockAt: 1500) + } + } + } + + GovernanceUnlocksTestBuilding.expect { + UnlockScheduleTestBuilding.ScheduleResult.availableItem(amount: 91) { + GovernanceUnlockSchedule.Action.unlock(track: 21) + } + + UnlockScheduleTestBuilding.ScheduleResult.remainingItems { + UnlockScheduleTestBuilding.unlock(amount: 9, atBlock: 1500) { + GovernanceUnlockSchedule.Action.unvote(track: 21, index: 5) + GovernanceUnlockSchedule.Action.unlock(track: 21) + } + + UnlockScheduleTestBuilding.unlock(amount: 1, atBlock: 2000) { + GovernanceUnlockSchedule.Action.unvote(track: 20, index: 13) + GovernanceUnlockSchedule.Action.unlock(track: 20) + } + } + } + } + } } From 0c3d72f2781cf71a987d48b5dcbf297e23294a8b Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 31 Oct 2022 11:37:29 +0500 Subject: [PATCH 134/229] refactoring --- .../Locks/Gov2UnlocksCalculator.swift | 40 +++++++++---------- .../Governance/Gov2UnlockScheduleTests.swift | 34 ++++++++-------- .../GovernanceUnlocksTestBuilding.swift | 8 ++-- 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift index 2589d2e33a..e7e24fc536 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift @@ -2,50 +2,46 @@ import Foundation import BigInt /** - * Given the information about Voting (priors + active votes), statuses of referenda and TrackLocks + * Given the information about Voting (priors + active votes), statuses of referenda and track locks * Constructs the estimated claiming schedule. * The schedule is exact when all involved referenda are completed. Only ongoing referenda' end time is estimateted * * The claiming schedule shows how much tokens will be unlocked and when. - * Schedule may consist of zero or one [ClaimSchedule.UnlockChunk.Claimable] chunk - * and zero or more [ClaimSchedule.UnlockChunk.Pending] chunks. - * - * [ClaimSchedule.UnlockChunk.Pending] chunks also provides a set of [ClaimSchedule.ClaimAction] actions - * needed to claim whole chunk. + * Schedule may consist of zero or more [GovernanceUnlockSchedule.Item] with corresponding actions to do. * * The algorithm itself consists of several parts * * 1. Determine individual unlocks - * This step is based on prior [Voting.Casting.prior] and [AccountVote.Standard] standard votes - * a. Each non-zero prior has a single individual unlock + * This step is based on prior [ConvictionVoting.PriorLock], [ConvictionVoting.AccountVote], + * [ConvictionVoting.Delegating] + * a. Each non-zero prior (both from casting and delegating) has a single individual unlock * b. Each non-zero vote has a single individual unlock. * However, unlock time for votes is at least unlock time of corresponding prior. * c. Find a gap between [voting] and [trackLocks], which indicates an extra claimable amount * To provide additive effect of gap, we add total voting lock on top of it: - if [voting] has some pending locks - they gonna delay their amount but always leaving trackGap untouched & claimable - On the other hand, if other tracks have locks bigger than [voting]'s total lock, - trackGap will be partially or full delayed by them + * if [voting] has some pending locks - they gonna delay their amount but always leaving + * trackGap untouched & claimable. + * On the other hand, if other tracks have locks bigger than [voting]'s total lock, + * trackGap will be partially or full delayed by them * - * During this step we also determine the list of [ClaimAffect], - * which later gets translated to [ClaimSchedule.ClaimAction]. + * During this step we also determine the set of [GovernanceUnlockSchedule.Action] * * 2. Combine all locks with the same unlock time into single lock * a. Result's amount is the maximum between combined locks * b. Result's affects is a concatenation of all affects from combined locks * * 3. Construct preliminary unlock schedule based on the following algorithm - * a. Sort pairs from step (2) by descending [ClaimableLock.claimAt] order - * b. For each item in the sorted list, find the difference between the biggest currently processed lock and item's amount + * a. Sort pairs from step (2) by descending [GovernanceUnlockSchedule.Item.unlockAt] order; + * b. For each item in the sorted list, find the difference between the biggest currently + * processed lock and item's amount; * c. Since we start from the most far locks in the future, finding a positive difference means that * this difference is actually an entry in desired unlock schedule. Negative difference means that this unlock is - * completely covered by future's unlock with bigger amount. Thus, we should discard it from the schedule and move its affects - * to the currently known maximum lock in order to not to loose its actions when unlocking maximum lock. + * completely covered by future's unlock with bigger amount. + * Thus, we should discard it from the schedule and move its affects to the currently known maximum lock + * in order to not to loose its actions when unlocking maximum lock. * - * 4. Check which if unlocks are claimable and which are not by constructing [ClaimSchedule.UnlockChunk] based on [currentBlockNumber] - * 5. Fold all [ClaimSchedule.UnlockChunk] into single chunk. - * 6. If gap exists, then we should add it to claimable chunk. We should also check if we should perform extra [ClaimSchedule.ClaimAction.Unlock] - * for each track that is included in the gap. We do that by finding by checking which [ClaimSchedule.ClaimAction.Unlock] unlocks are already present - * in claimable chunk's actions in order to not to do them twice. + * 4. To find which unlocks are claimable one should call [GovernanceUnlockSchedule.availableItem(at:)] + * function by providing current block number; */ final class Gov2UnlocksCalculator { private func createUnlocksFromVotes( diff --git a/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift b/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift index a4c704684d..33dc87fe7a 100644 --- a/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift +++ b/novawalletTests/Modules/Governance/Gov2UnlockScheduleTests.swift @@ -15,7 +15,7 @@ class Gov2UnlockScheduleTests: XCTestCase { GovernanceUnlocksTestBuilding.given { TrackTestBuilding.track(0) { TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 0, balance: 1, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 0, amount: 1, unlockAt: 1000) } } } @@ -61,7 +61,7 @@ class Gov2UnlockScheduleTests: XCTestCase { TrackTestBuilding.track(0) { TrackTestBuilding.VotingParams.prior(amount: 1, unlockAt: 1100) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 1, balance: 2, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 1, amount: 2, unlockAt: 1000) } } } @@ -82,8 +82,8 @@ class Gov2UnlockScheduleTests: XCTestCase { GovernanceUnlocksTestBuilding.given { TrackTestBuilding.track(0) { TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 0, balance: 8, unlockAt: 1000) - TrackTestBuilding.Vote(referendum: 1, balance: 2, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 0, amount: 8, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 1, amount: 2, unlockAt: 1000) } } } @@ -104,7 +104,7 @@ class Gov2UnlockScheduleTests: XCTestCase { TrackTestBuilding.track(0) { TrackTestBuilding.VotingParams.prior(amount: 1, unlockAt: 1100) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 1, balance: 2, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 1, amount: 2, unlockAt: 1000) } } } @@ -124,13 +124,13 @@ class Gov2UnlockScheduleTests: XCTestCase { TrackTestBuilding.track(0) { TrackTestBuilding.VotingParams.locked(0) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 0, balance: 1, unlockAt: 1100) + TrackTestBuilding.Vote(referendum: 0, amount: 1, unlockAt: 1100) } } TrackTestBuilding.track(1) { TrackTestBuilding.VotingParams.locked(0) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 1, balance: 2, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 1, amount: 2, unlockAt: 1000) } } } @@ -152,19 +152,19 @@ class Gov2UnlockScheduleTests: XCTestCase { TrackTestBuilding.track(1) { TrackTestBuilding.VotingParams.locked(0) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 1, balance: 1, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 1, amount: 1, unlockAt: 1000) } } TrackTestBuilding.track(2) { TrackTestBuilding.VotingParams.locked(0) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 2, balance: 2, unlockAt: 1100) + TrackTestBuilding.Vote(referendum: 2, amount: 2, unlockAt: 1100) } } TrackTestBuilding.track(3) { TrackTestBuilding.VotingParams.locked(0) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 3, balance: 1, unlockAt: 1200) + TrackTestBuilding.Vote(referendum: 3, amount: 1, unlockAt: 1200) } } } @@ -188,7 +188,7 @@ class Gov2UnlockScheduleTests: XCTestCase { TrackTestBuilding.track(0) { TrackTestBuilding.VotingParams.locked(10) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 0, balance: 2, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 0, amount: 2, unlockAt: 1000) } } } @@ -208,7 +208,7 @@ class Gov2UnlockScheduleTests: XCTestCase { TrackTestBuilding.track(0) { TrackTestBuilding.VotingParams.locked(10) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 0, balance: 1, unlockAt: 1000) + TrackTestBuilding.Vote(referendum: 0, amount: 1, unlockAt: 1000) } } @@ -282,9 +282,9 @@ class Gov2UnlockScheduleTests: XCTestCase { GovernanceUnlocksTestBuilding.given { TrackTestBuilding.track(0) { TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 0, balance: 3, unlockAt: 1100) - TrackTestBuilding.Vote(referendum: 2, balance: 2, unlockAt: 1200) - TrackTestBuilding.Vote(referendum: 1, balance: 1, unlockAt: 1300) + TrackTestBuilding.Vote(referendum: 0, amount: 3, unlockAt: 1100) + TrackTestBuilding.Vote(referendum: 2, amount: 2, unlockAt: 1200) + TrackTestBuilding.Vote(referendum: 1, amount: 1, unlockAt: 1300) } } } @@ -316,14 +316,14 @@ class Gov2UnlockScheduleTests: XCTestCase { TrackTestBuilding.track(20) { TrackTestBuilding.VotingParams.locked(1) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 13, balance: 1, unlockAt: 2000) + TrackTestBuilding.Vote(referendum: 13, amount: 1, unlockAt: 2000) } } TrackTestBuilding.track(21) { TrackTestBuilding.VotingParams.locked(101) TrackTestBuilding.VotingParams.votes { - TrackTestBuilding.Vote(referendum: 5, balance: 10, unlockAt: 1500) + TrackTestBuilding.Vote(referendum: 5, amount: 10, unlockAt: 1500) } } } diff --git a/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift b/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift index 18d3eaece0..dba3d41763 100644 --- a/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift +++ b/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift @@ -178,7 +178,7 @@ enum TrackTestBuilding { .standard( .init( vote: .init(aye: vote.isAye, conviction: vote.conviction), - balance: vote.balance + balance: vote.amount ) ), referendumId: vote.referendum @@ -226,20 +226,20 @@ enum TrackTestBuilding { struct Vote { let referendum: ReferendumIdLocal - let balance: BigUInt + let amount: BigUInt let conviction: ConvictionVoting.Conviction let unlockAt: BlockNumber let isAye: Bool init( referendum: ReferendumIdLocal, - balance: BigUInt, + amount: BigUInt, unlockAt: BlockNumber, conviction: ConvictionVoting.Conviction = .locked1x, isAye: Bool = true ) { self.referendum = referendum - self.balance = balance + self.amount = amount self.unlockAt = unlockAt self.conviction = conviction self.isAye = isAye From e6a434b3fcd6d9d61529f449fdb2754fdabb7bf1 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 31 Oct 2022 14:22:38 +0500 Subject: [PATCH 135/229] add unlock schedule retrieve logic --- .../Model/ReferendumsInteractorError.swift | 3 +- .../Referendums/ReferendumsInteractor.swift | 113 ++++++++++-------- .../Referendums/ReferendumsPresenter.swift | 57 +++++++-- .../Referendums/ReferendumsProtocols.swift | 4 +- .../Parent/VoteChildPresenterFactory.swift | 6 + 5 files changed, 118 insertions(+), 65 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift index 3f12c666a9..4084971b02 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/Model/ReferendumsInteractorError.swift @@ -8,7 +8,8 @@ enum ReferendumsInteractorError: Error { case referendumsFetchFailed(_ internalError: Error) case blockNumberSubscriptionFailed(_ internalError: Error) case metadataSubscriptionFailed(_ internalError: Error) - case votesFetchFailed(_ internalError: Error) + case votingSubscriptionFailed(_ internalError: Error) case blockTimeFetchFailed(_ internalError: Error) case blockTimeServiceFailed(_ internalError: Error) + case unlockScheduleFetchFailed(_ internalError: Error) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 429aa56068..7f8bc8f43e 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -12,6 +12,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let referendumsOperationFactory: ReferendumsOperationFactoryProtocol + let lockStateFactory: GovernanceLockStateFactoryProtocol let applicationHandler: ApplicationHandlerProtocol let serviceFactory: GovernanceServiceFactoryProtocol let operationQueue: OperationQueue @@ -32,8 +33,8 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani private lazy var localKeyFactory = LocalStorageKeyFactory() private var referendumsCancellable: CancellableCall? - private var votesCancellable: CancellableCall? private var blockTimeCancellable: CancellableCall? + private var unlockScheduleCancellable: CancellableCall? init( selectedMetaAccount: MetaAccountModel, @@ -42,6 +43,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, referendumsOperationFactory: ReferendumsOperationFactoryProtocol, + lockStateFactory: GovernanceLockStateFactoryProtocol, serviceFactory: GovernanceServiceFactoryProtocol, applicationHandler: ApplicationHandlerProtocol, operationQueue: OperationQueue, @@ -53,6 +55,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory self.referendumsOperationFactory = referendumsOperationFactory + self.lockStateFactory = lockStateFactory self.serviceFactory = serviceFactory self.operationQueue = operationQueue self.applicationHandler = applicationHandler @@ -79,8 +82,8 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani private func clearCancellable() { clear(cancellable: &referendumsCancellable) - clear(cancellable: &votesCancellable) clear(cancellable: &blockTimeCancellable) + clear(cancellable: &unlockScheduleCancellable) } private func clearBlockTimeService() { @@ -123,6 +126,10 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani subscribeToBlockNumber(for: chain) subscribeToMetadata(for: chain) + + if let accountId = accountId { + subscribeAccountVotes(for: accountId) + } } private func setupBlockTimeService(for chain: ChainModel) { @@ -258,58 +265,21 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } - private func provideVotesIfNeeded() { - guard votesCancellable == nil else { - return - } - - guard let chain = governanceState.settings.value else { - presenter?.didReceiveError(.votesFetchFailed(PersistentValueSettingsError.missingValue)) - return - } - - guard let connection = chainRegistry.getConnection(for: chain.chainId) else { - presenter?.didReceiveError(.votesFetchFailed(ChainRegistryError.connectionUnavailable)) - return - } - - guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { - presenter?.didReceiveError(.votesFetchFailed(ChainRegistryError.runtimeMetadaUnavailable)) - return - } - - guard let accountId = selectedMetaAccount.fetch(for: chain.accountRequest())?.accountId else { - presenter?.didReceiveVotes([:]) + private func subscribeAccountVotes(for accountId: AccountId) { + guard let subscriptionFactory = governanceState.subscriptionFactory else { return } - let wrapper = referendumsOperationFactory.fetchAccountVotesWrapper( - for: accountId, - from: connection, - runtimeProvider: runtimeProvider, - blockHash: nil - ) - - wrapper.targetOperation.completionBlock = { [weak self] in - DispatchQueue.main.async { - guard wrapper === self?.votesCancellable else { - return - } - - self?.votesCancellable = nil - - do { - let votes = try wrapper.targetOperation.extractNoCancellableResultData().votes - self?.presenter?.didReceiveVotes(votes) - } catch { - self?.presenter?.didReceiveError(.votesFetchFailed(error)) - } + subscriptionFactory.subscribeToAccountVotes(self, accountId: accountId) { [weak self] result in + switch result { + case let .success(voting): + self?.presenter?.didReceiveVoting(voting) + case let .failure(error): + self?.presenter?.didReceiveError(.votingSubscriptionFailed(error)) + case .none: + break } } - - votesCancellable = wrapper - - operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } } @@ -369,13 +339,56 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { func refresh() { if governanceState.settings.value != nil { provideReferendumsIfNeeded() - provideVotesIfNeeded() provideBlockTime() metadataProvider?.refresh() } } + func refreshUnlockSchedule(for tracksVoting: ReferendumTracksVotingDistribution, blockHash: Data?) { + if let chain = governanceState.settings.value { + clear(cancellable: &referendumsCancellable) + + guard let connection = chainRegistry.getConnection(for: chain.chainId) else { + presenter?.didReceiveError(.unlockScheduleFetchFailed(ChainRegistryError.connectionUnavailable)) + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + presenter?.didReceiveError(.unlockScheduleFetchFailed(ChainRegistryError.runtimeMetadaUnavailable)) + return + } + + let wrapper = lockStateFactory.buildUnlockScheduleWrapper( + for: tracksVoting, + from: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard self?.unlockScheduleCancellable === wrapper else { + return + } + + self?.unlockScheduleCancellable = nil + + do { + let schedule = try wrapper.targetOperation.extractNoCancellableResultData() + self?.presenter?.didReceiveUnlockSchedule(schedule) + } catch { + self?.presenter?.didReceiveError(.unlockScheduleFetchFailed(error)) + } + } + } + + unlockScheduleCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } + } + func retryBlockTime() { provideBlockTime() } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 49e507d726..603d09b1a9 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -17,7 +17,8 @@ final class ReferendumsPresenter { private var price: PriceData? private var referendums: [ReferendumLocal]? private var referendumsMetadata: ReferendumMetadataMapping? - private var votes: [ReferendumIdLocal: ReferendumAccountVoteLocal]? + private var voting: CallbackStorageSubscriptionResult? + private var unlockSchedule: GovernanceUnlockSchedule? private var blockNumber: BlockNumber? private var blockTime: BlockTime? @@ -56,7 +57,7 @@ final class ReferendumsPresenter { price = nil referendums = nil referendumsMetadata = nil - votes = nil + voting = nil blockNumber = nil blockTime = nil maxStatusTimeInterval = nil @@ -79,7 +80,9 @@ final class ReferendumsPresenter { view?.didReceiveChainBalance(viewModel: viewModel) } - private func updateView() { + private func updateUnlocksView() {} + + private func updateReferendumsView() { guard let view = view else { return } @@ -89,10 +92,12 @@ final class ReferendumsPresenter { let chainModel = chain else { return } + + let accountVotes = voting?.value?.votes let sections = viewModelFactory.createSections(input: .init( referendums: referendums, metadataMapping: referendumsMetadata, - votes: votes ?? [:], + votes: accountVotes?.votes ?? [:], chainInfo: .init(chain: chainModel, currentBlock: currentBlock, blockDuration: blockTime), locale: selectedLocale )) @@ -178,6 +183,14 @@ final class ReferendumsPresenter { self.timeModels = updatedTimeModels view.updateReferendums(time: updatedTimeModels) } + + private func refreshUnlockSchedule() { + guard let tracksVoting = voting?.value else { + return + } + + interactor.refreshUnlockSchedule(for: tracksVoting, blockHash: nil) + } } extension ReferendumsPresenter: ReferendumsPresenterProtocol { @@ -186,10 +199,12 @@ extension ReferendumsPresenter: ReferendumsPresenterProtocol { return } + let accountVotes = voting?.value?.votes + wireframe.showReferendumDetails( from: view, referendum: referendum, - accountVotes: votes?[referendum.index], + accountVotes: accountVotes?.votes[referendum.index], metadata: referendumsMetadata?[referendum.index] ) } @@ -224,13 +239,17 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { } extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { - func didReceiveVotes(_ votes: [ReferendumIdLocal: ReferendumAccountVoteLocal]) { - self.votes = votes + func didReceiveVoting(_ voting: CallbackStorageSubscriptionResult) { + self.voting = voting + updateReferendumsView() + updateUnlocksView() + + refreshUnlockSchedule() } func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) { referendumsMetadata = metadata - updateView() + updateReferendumsView() } func didReceiveBlockNumber(_ blockNumber: BlockNumber) { @@ -248,15 +267,17 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { func didReceiveReferendums(_ referendums: [ReferendumLocal]) { self.referendums = referendums.sorted { sorting.compare(referendum1: $0, referendum2: $1) } - updateView() + updateReferendumsView() updateTimeModels() + + refreshUnlockSchedule() } func didReceiveSelectedChain(_ chain: ChainModel) { self.chain = chain provideChainBalance() - updateView() + updateReferendumsView() } func didReceiveAssetBalance(_ balance: AssetBalance?) { @@ -269,6 +290,11 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { self.price = price } + func didReceiveUnlockSchedule(_ unlockSchedule: GovernanceUnlockSchedule) { + self.unlockSchedule = unlockSchedule + updateUnlocksView() + } + func didReceiveError(_ error: ReferendumsInteractorError) { logger.error("Did receive error: \(error)") @@ -283,12 +309,12 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { self?.interactor.saveSelected(chainModel: chain) } } - case .referendumsFetchFailed, .votesFetchFailed: + case .referendumsFetchFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in self?.interactor.refresh() } case .blockNumberSubscriptionFailed, .priceSubscriptionFailed, .balanceSubscriptionFailed, - .metadataSubscriptionFailed, .blockTimeServiceFailed: + .metadataSubscriptionFailed, .blockTimeServiceFailed, .votingSubscriptionFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in self?.interactor.remakeSubscriptions() } @@ -296,6 +322,10 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in self?.interactor.retryBlockTime() } + case .unlockScheduleFetchFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.refreshUnlockSchedule() + } } } } @@ -321,7 +351,8 @@ extension ReferendumsPresenter: Localizable { if let view = view, view.isSetup { provideChainBalance() - updateView() + updateReferendumsView() + updateUnlocksView() } } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 733ebfe731..0a58250f9a 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -18,6 +18,7 @@ protocol ReferendumsInteractorInputProtocol: AnyObject { func becomeOnline() func putOffline() func refresh() + func refreshUnlockSchedule(for tracksVoting: ReferendumTracksVotingDistribution, blockHash: Data?) func remakeSubscriptions() func retryBlockTime() } @@ -25,12 +26,13 @@ protocol ReferendumsInteractorInputProtocol: AnyObject { protocol ReferendumsInteractorOutputProtocol: AnyObject { func didReceiveReferendums(_ referendums: [ReferendumLocal]) func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) - func didReceiveVotes(_ votes: [ReferendumIdLocal: ReferendumAccountVoteLocal]) + func didReceiveVoting(_ voting: CallbackStorageSubscriptionResult) func didReceiveSelectedChain(_ chain: ChainModel) func didReceiveAssetBalance(_ balance: AssetBalance?) func didReceivePrice(_ price: PriceData?) func didReceiveBlockNumber(_ blockNumber: BlockNumber) func didReceiveBlockTime(_ blockTime: BlockTime) + func didReceiveUnlockSchedule(_ unlockSchedule: GovernanceUnlockSchedule) func didReceiveError(_ error: ReferendumsInteractorError) } diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index e488768604..d979495ac4 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -120,6 +120,11 @@ final class VoteChildPresenterFactory { logger: logger ) + let lockStateFactory = Gov2LockStateFactory( + requestFactory: requestFactory, + unlocksCalculator: Gov2UnlocksCalculator() + ) + return ReferendumsInteractor( selectedMetaAccount: wallet, governanceState: state, @@ -127,6 +132,7 @@ final class VoteChildPresenterFactory { walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, priceLocalSubscriptionFactory: priceProviderFactory, referendumsOperationFactory: referendumOperationFactory, + lockStateFactory: lockStateFactory, serviceFactory: serviceFactory, applicationHandler: applicationHandler, operationQueue: operationQueue, From 61d0c43b5489c245de86907c58beb8856d201b40 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 31 Oct 2022 23:20:10 +0500 Subject: [PATCH 136/229] add locks widget --- novawallet.xcodeproj/project.pbxproj | 8 ++ .../Crowdloan/View/BlurredTableViewCell.swift | 10 ++ .../Model/ReferendumVotingLocal.swift | 4 + .../Referendums/ReferendumsPresenter.swift | 33 ++++++- .../Referendums/ReferendumsProtocols.swift | 2 + .../Referendums/ReferendumsViewManager.swift | 99 ++++++++++++++----- .../View/ReferendumTableViewCell.swift | 1 + .../ReferendumsUnlocksTableViewCell.swift | 72 ++++++++++++++ .../Vote/Governance/View/UILabel+Style.swift | 6 ++ .../ReferendumsUnlocksViewModel.swift | 6 ++ .../Parent/VoteChildPresenterFactory.swift | 5 +- novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 13 files changed, 223 insertions(+), 25 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/View/ReferendumsUnlocksTableViewCell.swift create mode 100644 novawallet/Modules/Vote/Governance/ViewModel/ReferendumsUnlocksViewModel.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 7cefecc548..d336815c6b 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -342,6 +342,8 @@ 8402CC9C275B92AC00E5BF30 /* ControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8402CC9B275B92AC00E5BF30 /* ControlView.swift */; }; 8402CC9E275B946100E5BF30 /* DAppItemViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8402CC9D275B946100E5BF30 /* DAppItemViewCell.swift */; }; 84031C17263EC95C008FD9D4 /* SetPayeeCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84031C16263EC95C008FD9D4 /* SetPayeeCall.swift */; }; + 84033055290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84033054290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift */; }; + 84033057290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84033056290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift */; }; 84038FEC26FFBA4D00C73F3F /* PriceLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84038FEB26FFBA4D00C73F3F /* PriceLocalStorageSubscriber.swift */; }; 84038FEE26FFBA6200C73F3F /* PriceLocalSubscriptionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84038FED26FFBA6200C73F3F /* PriceLocalSubscriptionHandler.swift */; }; 84038FF026FFBE0600C73F3F /* JsonLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84038FEF26FFBE0600C73F3F /* JsonLocalStorageSubscriber.swift */; }; @@ -3267,6 +3269,8 @@ 8402CC9B275B92AC00E5BF30 /* ControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlView.swift; sourceTree = ""; }; 8402CC9D275B946100E5BF30 /* DAppItemViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppItemViewCell.swift; sourceTree = ""; }; 84031C16263EC95C008FD9D4 /* SetPayeeCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetPayeeCall.swift; sourceTree = ""; }; + 84033054290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsUnlocksViewModel.swift; sourceTree = ""; }; + 84033056290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsUnlocksTableViewCell.swift; sourceTree = ""; }; 84038FEB26FFBA4D00C73F3F /* PriceLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceLocalStorageSubscriber.swift; sourceTree = ""; }; 84038FED26FFBA6200C73F3F /* PriceLocalSubscriptionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceLocalSubscriptionHandler.swift; sourceTree = ""; }; 84038FEF26FFBE0600C73F3F /* JsonLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JsonLocalStorageSubscriber.swift; sourceTree = ""; }; @@ -7991,6 +7995,7 @@ 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */, 848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */, 8487010B2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift */, + 84033054290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -12270,6 +12275,7 @@ 889D889428F01E5B00C4320F /* ReferendumTableViewCell.swift */, 889D889628F022AA00C4320F /* UILabel+Style.swift */, 88F34FDC28FFE6E400712BDE /* MultiValueView+Model.swift */, + 84033056290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift */, ); path = View; sourceTree = ""; @@ -16759,6 +16765,7 @@ 8321399396FA5B25BC93A090 /* DAppPhishingViewLayout.swift in Sources */, B1BB78684B059A113AB3AD30 /* DAppPhishingViewFactory.swift in Sources */, 6ECB27B386124F87382073FD /* DAppAddFavoriteProtocols.swift in Sources */, + 84033057290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift in Sources */, 433A3C2B0D1E4BA5974D681B /* DAppAddFavoriteWireframe.swift in Sources */, F5CA222FA684AAC8B556E667 /* DAppAddFavoritePresenter.swift in Sources */, AC904E313DC15AE40C927946 /* DAppAddFavoriteInteractor.swift in Sources */, @@ -17038,6 +17045,7 @@ 85600C63BB1BEC76EDFA04CB /* ReferendumFullDetailsViewController.swift in Sources */, EAAFB082E2BB0CA418714061 /* ReferendumFullDetailsViewLayout.swift in Sources */, 74F470AE889B0E49D9808802 /* ReferendumFullDetailsViewFactory.swift in Sources */, + 84033055290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift in Sources */, 003063A17B04BA6327EA355F /* ReferendumVotersProtocols.swift in Sources */, E4021A6E90432CC5C797A647 /* ReferendumVotersWireframe.swift in Sources */, 93EB8C73108944E9C576936C /* ReferendumVotersPresenter.swift in Sources */, diff --git a/novawallet/Modules/Vote/Crowdloan/View/BlurredTableViewCell.swift b/novawallet/Modules/Vote/Crowdloan/View/BlurredTableViewCell.swift index 9b16dfeb66..68856eda0b 100644 --- a/novawallet/Modules/Vote/Crowdloan/View/BlurredTableViewCell.swift +++ b/novawallet/Modules/Vote/Crowdloan/View/BlurredTableViewCell.swift @@ -4,6 +4,8 @@ class BlurredTableViewCell: UITableViewCell where TContentView: UI let view: TContentView = .init() let backgroundBlurView = TriangularedBlurView() + var shouldApplyHighlighting: Bool = false + var contentInsets: UIEdgeInsets = .init(top: 0, left: 16, bottom: 0, right: 16) { didSet { updateLayout() @@ -24,6 +26,14 @@ class BlurredTableViewCell: UITableViewCell where TContentView: UI setupLayout() } + override func setHighlighted(_ highlighted: Bool, animated: Bool) { + super.setHighlighted(highlighted, animated: animated) + + backgroundBlurView.overlayView.fillColor = shouldApplyHighlighting && highlighted ? + R.color.colorAccentSelected()! + : .clear + } + @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift index 32497d785d..7ef309e3b3 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumVotingLocal.swift @@ -119,4 +119,8 @@ struct ReferendumAccountVotingDistribution { struct ReferendumTracksVotingDistribution { let votes: ReferendumAccountVotingDistribution let trackLocks: [ConvictionVoting.ClassLock] + + func totalLocked() -> BigUInt { + trackLocks.reduce(BigUInt(0)) { max($0, $1.amount) } + } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 603d09b1a9..7d19ee7f3c 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -9,6 +9,7 @@ final class ReferendumsPresenter { let wireframe: ReferendumsWireframeProtocol let viewModelFactory: ReferendumsModelFactoryProtocol let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol + let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol let sorting: ReferendumsSorting let logger: LoggerProtocol @@ -37,6 +38,7 @@ final class ReferendumsPresenter { wireframe: ReferendumsWireframeProtocol, viewModelFactory: ReferendumsModelFactoryProtocol, statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol, + assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, sorting: ReferendumsSorting, localizationManager: LocalizationManagerProtocol, logger: LoggerProtocol @@ -45,6 +47,7 @@ final class ReferendumsPresenter { self.wireframe = wireframe self.viewModelFactory = viewModelFactory self.statusViewModelFactory = statusViewModelFactory + self.assetBalanceFormatterFactory = assetBalanceFormatterFactory self.sorting = sorting self.logger = logger self.localizationManager = localizationManager @@ -63,6 +66,7 @@ final class ReferendumsPresenter { maxStatusTimeInterval = nil timeModels = nil + view?.didReceiveUnlocks(viewModel: nil) view?.update(model: .init(sections: [])) } @@ -80,7 +84,32 @@ final class ReferendumsPresenter { view?.didReceiveChainBalance(viewModel: viewModel) } - private func updateUnlocksView() {} + private func updateUnlocksView() { + guard + let totalLocked = voting?.value?.totalLocked(), + totalLocked > 0, + let displayInfo = chain?.utilityAssetDisplayInfo() + else { + view?.didReceiveUnlocks(viewModel: nil) + return + } + + let totalLockedDecimal = Decimal.fromSubstrateAmount(totalLocked, precision: displayInfo.assetPrecision) ?? 0 + + let tokenFormatter = assetBalanceFormatterFactory.createTokenFormatter(for: displayInfo) + let totalLockedString = tokenFormatter.value(for: selectedLocale).stringFromDecimal(totalLockedDecimal) + + let hasUnlock: Bool + + if let blockNumber = blockNumber, let unlockSchedule = unlockSchedule { + hasUnlock = unlockSchedule.availableUnlock(at: blockNumber).amount > 0 + } else { + hasUnlock = false + } + + let viewModel = ReferendumsUnlocksViewModel(totalLock: totalLockedString ?? "", hasUnlock: hasUnlock) + view?.didReceiveUnlocks(viewModel: viewModel) + } private func updateReferendumsView() { guard let view = view else { @@ -236,6 +265,8 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { selectedChainAssetId: chainAssetId ) } + + func selectUnlocks() {} } extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 0a58250f9a..439dbc0b0b 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -6,10 +6,12 @@ protocol ReferendumsViewProtocol: ControllerBackedProtocol { func didReceiveChainBalance(viewModel: ChainBalanceViewModel) func update(model: ReferendumsViewModel) func updateReferendums(time: [UInt: StatusTimeViewModel?]) + func didReceiveUnlocks(viewModel: ReferendumsUnlocksViewModel?) } protocol ReferendumsPresenterProtocol: AnyObject { func select(referendumIndex: UInt) + func selectUnlocks() } protocol ReferendumsInteractorInputProtocol: AnyObject { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 078d52394e..8ec7af5438 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -2,9 +2,14 @@ import Foundation import UIKit final class ReferendumsViewManager: NSObject { + private enum Constants { + static let unlocksCellHeight: CGFloat = 52 + } + let tableView: UITableView let chainSelectionView: VoteChainViewProtocol - private var model: ReferendumsViewModel = .init(sections: []) + private var referendumsViewModel: ReferendumsViewModel = .init(sections: []) + private var unlocksViewModel: ReferendumsUnlocksViewModel? var locale = Locale.current { didSet { @@ -28,25 +33,43 @@ final class ReferendumsViewManager: NSObject { extension ReferendumsViewManager: UITableViewDataSource { func numberOfSections(in _: UITableView) -> Int { - model.sections.count + referendumsViewModel.sections.count + 1 } func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { - switch model.sections[section] { - case let .active(_, cells), let .completed(_, cells): - return cells.count + if section == 0 { + return unlocksViewModel != nil ? 1 : 0 + } else { + let referendumsSection = section - 1 + switch referendumsViewModel.sections[referendumsSection] { + case let .active(_, cells), let .completed(_, cells): + return cells.count + } } } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell: ReferendumTableViewCell = tableView.dequeueReusableCell(for: indexPath) - cell.applyStyle() - let section = model.sections[indexPath.section] - switch section { - case let .active(_, cellModels), let .completed(_, cellModels): - let cellModel = cellModels[indexPath.row].viewModel - cell.view.bind(viewModel: cellModel) - return cell + if indexPath.section == 0 { + let unlocksCell: ReferendumsUnlocksTableViewCell = tableView.dequeueReusableCell(for: indexPath) + unlocksCell.applyStyle() + + if let viewModel = unlocksViewModel { + unlocksCell.view.bind(viewModel: viewModel, locale: locale) + } + + return unlocksCell + } else { + let cell: ReferendumTableViewCell = tableView.dequeueReusableCell(for: indexPath) + cell.applyStyle() + + let referendumsCell = indexPath.section - 1 + let section = referendumsViewModel.sections[referendumsCell] + switch section { + case let .active(_, cellModels), let .completed(_, cellModels): + let cellModel = cellModels[indexPath.row].viewModel + cell.view.bind(viewModel: cellModel) + return cell + } } } } @@ -55,16 +78,26 @@ extension ReferendumsViewManager: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) - let section = model.sections[indexPath.section] - switch section { - case let .active(_, cellModels), let .completed(_, cellModels): - let referendumIndex = cellModels[indexPath.row].referendumIndex - presenter?.select(referendumIndex: referendumIndex) + if indexPath.section == 0 { + presenter?.selectUnlocks() + } else { + let referendumsSection = indexPath.section - 1 + let section = referendumsViewModel.sections[referendumsSection] + switch section { + case let .active(_, cellModels), let .completed(_, cellModels): + let referendumIndex = cellModels[indexPath.row].referendumIndex + presenter?.select(referendumIndex: referendumIndex) + } } } func tableView(_: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let sectionModel = model.sections[section] + guard section > 0 else { + return nil + } + + let referendumsSection = section - 1 + let sectionModel = referendumsViewModel.sections[referendumsSection] switch sectionModel { case let .active(title, cells), let .completed(title, cells): let headerView: VoteStatusSectionView = tableView.dequeueReusableHeaderFooterView() @@ -80,8 +113,20 @@ extension ReferendumsViewManager: UITableViewDelegate { } } - func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat { - UITableView.automaticDimension + func tableView(_: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + if section > 0 { + return UITableView.automaticDimension + } else { + return 0 + } + } + + func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + if indexPath.section > 0 { + return UITableView.automaticDimension + } else { + return Constants.unlocksCellHeight + } } } @@ -91,7 +136,7 @@ extension ReferendumsViewManager: ReferendumsViewProtocol { } func update(model: ReferendumsViewModel) { - self.model = model + referendumsViewModel = model tableView.reloadData() } @@ -102,7 +147,8 @@ extension ReferendumsViewManager: ReferendumsViewProtocol { return } - switch model.sections[indexPath.section] { + let referendumsSection = indexPath.section - 1 + switch referendumsViewModel.sections[referendumsSection] { case let .active(_, cells), let .completed(_, cells): let cellModel = cells[indexPath.row] guard let timeModel = time[cellModel.referendumIndex]??.viewModel else { @@ -113,6 +159,11 @@ extension ReferendumsViewManager: ReferendumsViewProtocol { } } } + + func didReceiveUnlocks(viewModel: ReferendumsUnlocksViewModel?) { + unlocksViewModel = viewModel + tableView.reloadData() + } } extension ReferendumsViewManager: VoteChildViewProtocol { @@ -128,6 +179,7 @@ extension ReferendumsViewManager: VoteChildViewProtocol { tableView.dataSource = self tableView.delegate = self tableView.registerClassForCell(ReferendumTableViewCell.self) + tableView.registerClassForCell(ReferendumsUnlocksTableViewCell.self) tableView.registerHeaderFooterView(withClass: VoteStatusSectionView.self) tableView.reloadData() } @@ -136,6 +188,7 @@ extension ReferendumsViewManager: VoteChildViewProtocol { tableView.dataSource = nil tableView.delegate = nil tableView.unregisterClassForCell(ReferendumTableViewCell.self) + tableView.unregisterClassForCell(ReferendumsUnlocksTableViewCell.self) tableView.unregisterHeaderFooterView(withClass: VoteStatusSectionView.self) tableView.reloadData() } diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift b/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift index 2a0d2166a1..e0ad82fea9 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift @@ -37,6 +37,7 @@ typealias ReferendumTableViewCell = BlurredTableViewCell extension ReferendumTableViewCell { func applyStyle() { + shouldApplyHighlighting = true contentInsets = .init(top: 8, left: 16, bottom: 8, right: 16) innerInsets = .init(top: 16, left: 16, bottom: 16, right: 16) } diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumsUnlocksTableViewCell.swift b/novawallet/Modules/Vote/Governance/View/ReferendumsUnlocksTableViewCell.swift new file mode 100644 index 0000000000..ca3b34637f --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/ReferendumsUnlocksTableViewCell.swift @@ -0,0 +1,72 @@ +import UIKit + +final class ReferendumsUnlocksView: GenericTitleValueView< + GenericPairValueView, IconDetailsView +> { + var titleLabel: UILabel { + titleView.fView + } + + var locksLabel: UILabel { + titleView.sView.iconDetailsView.detailsLabel + } + + var unlocksLabel: UILabel { + valueView.detailsLabel + } + + override init(frame: CGRect) { + super.init(frame: frame) + + configure() + } + + func bind(viewModel: ReferendumsUnlocksViewModel, locale: Locale) { + titleLabel.text = R.string.localizable.walletBalanceLocked(preferredLanguages: locale.rLanguages) + locksLabel.text = viewModel.totalLock + unlocksLabel.text = viewModel.hasUnlock ? + R.string.localizable.commonUnlock(preferredLanguages: locale.rLanguages) : "" + } + + private func configure() { + titleView.setHorizontalAndSpacing(8.0) + + titleLabel.apply(style: .regularSubhedlineWhite) + + locksLabel.apply(style: .footnoteWhite64) + locksLabel.numberOfLines = 1 + + unlocksLabel.apply(style: .unlockStyle) + unlocksLabel.numberOfLines = 1 + + titleView.sView.backgroundView.fillColor = R.color.colorWhite16()! + titleView.sView.iconDetailsView.iconWidth = 12 + titleView.sView.iconDetailsView.spacing = 4 + titleView.sView.contentInsets = UIEdgeInsets(top: 3, left: 8, bottom: 3, right: 8) + titleView.sView.backgroundView.cornerRadius = 6 + titleView.sView.iconDetailsView.imageView.image = R.image.iconBrowserSecurity()?.tinted( + with: R.color.colorWhite64()! + ) + + valueView.mode = .detailsIcon + valueView.spacing = 4 + valueView.iconWidth = 24 + valueView.imageView.image = R.image.iconSmallArrow()?.tinted(with: R.color.colorWhite48()!) + } +} + +private extension UILabel.Style { + static var unlockStyle: UILabel.Style { + .init(textColor: R.color.colorGreen()!, font: .caption1) + } +} + +typealias ReferendumsUnlocksTableViewCell = BlurredTableViewCell + +extension ReferendumsUnlocksTableViewCell { + func applyStyle() { + shouldApplyHighlighting = true + contentInsets = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) + innerInsets = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) + } +} diff --git a/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift index dc0ddebb8a..c2481d38d1 100644 --- a/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift +++ b/novawallet/Modules/Vote/Governance/View/UILabel+Style.swift @@ -76,10 +76,16 @@ extension UILabel.Style { textColor: R.color.colorWhite64()!, font: .regularFootnote ) + static let caption1White64 = UILabel.Style( textColor: R.color.colorWhite64()!, font: .caption1 ) + + static let regularSubhedlineWhite = UILabel.Style( + textColor: R.color.colorWhite()!, + font: .regularSubheadline + ) } extension UILabel.Style { diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsUnlocksViewModel.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsUnlocksViewModel.swift new file mode 100644 index 0000000000..bb7feb1e0f --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsUnlocksViewModel.swift @@ -0,0 +1,6 @@ +import Foundation + +struct ReferendumsUnlocksViewModel { + let totalLock: String? + let hasUnlock: Bool +} diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index d979495ac4..e766538374 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -188,10 +188,12 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { let indexFormatter = NumberFormatter.index.localizableResource() + let assetBalanceFormatterFactory = AssetBalanceFormatterFactory() + let viewModelFactory = ReferendumsModelFactory( referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactory(indexFormatter: indexFormatter), statusViewModelFactory: statusViewModelFactory, - assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), + assetBalanceFormatterFactory: assetBalanceFormatterFactory, percentFormatter: NumberFormatter.referendumPercent.localizableResource(), indexFormatter: NumberFormatter.index.localizableResource(), quantityFormatter: NumberFormatter.quantity.localizableResource() @@ -202,6 +204,7 @@ extension VoteChildPresenterFactory: VoteChildPresenterFactoryProtocol { wireframe: wireframe, viewModelFactory: viewModelFactory, statusViewModelFactory: statusViewModelFactory, + assetBalanceFormatterFactory: assetBalanceFormatterFactory, sorting: ReferendumsTimeSortingProvider(), localizationManager: localizationManager, logger: logger diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index d731cbf951..534c7d434c 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1073,3 +1073,4 @@ "gov.reciprocal" = "Reciprocal"; "gov.unknown" = "Unknown"; "gov.in.queue.counter" = "(%@ of %@)"; +"common.unlock" = "Unlock"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index f1a73cb053..b811646a91 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1074,3 +1074,4 @@ "gov.reciprocal" = "Обратное линейное убывание"; "gov.unknown" = "Неизвестно"; "gov.in.queue.counter" = "(%@ из %@)"; +"common.unlock" = "Разблокировать"; From a34768dcc0ae59e70ee088b6eabe4b7957ff6bc3 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 31 Oct 2022 23:57:05 +0500 Subject: [PATCH 137/229] fix conviction multiplier --- .../ConvictionVoting/ConvictionVoting.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index 62cbcc3751..d1ef615709 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -34,13 +34,13 @@ enum ConvictionVoting { case .locked2x: return 2 * balance case .locked3x: - return 4 * balance + return 3 * balance case .locked4x: - return 8 * balance + return 4 * balance case .locked5x: - return 16 * balance + return 5 * balance case .locked6x: - return 32 * balance + return 6 * balance case .unknown: return nil } @@ -76,13 +76,13 @@ enum ConvictionVoting { case .locked2x: return 2 case .locked3x: - return 4 + return 3 case .locked4x: - return 8 + return 4 case .locked5x: - return 16 + return 5 case .locked6x: - return 32 + return 6 case .unknown: return nil } From 7079f44e2f4ba849d146b00746096d6186cf0678 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 1 Nov 2022 10:57:00 +0500 Subject: [PATCH 138/229] add unlock setup module --- novawallet.xcodeproj/project.pbxproj | 36 +++++++++++++++++++ .../GovernanceUnlockSetupInteractor.swift | 7 ++++ .../GovernanceUnlockSetupPresenter.swift | 21 +++++++++++ .../GovernanceUnlockSetupProtocols.swift | 11 ++++++ .../GovernanceUnlockSetupViewController.swift | 29 +++++++++++++++ .../GovernanceUnlockSetupViewFactory.swift | 17 +++++++++ .../GovernanceUnlockSetupViewLayout.swift | 13 +++++++ .../GovernanceUnlockSetupWireframe.swift | 3 ++ 8 files changed, 137 insertions(+) create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewLayout.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index d336815c6b..a57e315e40 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 0DF1E0D0CCEDC1340B7A47D7 /* TransferConfirmOnChainViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 899686C7351A2600FFA08371 /* TransferConfirmOnChainViewFactory.swift */; }; 0E364B6F05D390069D049CC2 /* DAppTxDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1039AA3654461114FBB86844 /* DAppTxDetailsPresenter.swift */; }; 0E6C2939AFB3D125C760D5A0 /* CrowdloanContributionSetupProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7484BA696561262926D87FE5 /* CrowdloanContributionSetupProtocols.swift */; }; + 0E71EA5AE04940824AEA01C7 /* GovernanceUnlockSetupViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2E14458DEC3317602A17527 /* GovernanceUnlockSetupViewLayout.swift */; }; 0F3E58FC800ED8722589F89E /* ReferralCrowdloanPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C503100478AB56E903598A78 /* ReferralCrowdloanPresenter.swift */; }; 0F5539A29F404F98DF6B2463 /* DAppAuthConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301287CBBF23EF58186A7BB5 /* DAppAuthConfirmViewLayout.swift */; }; 0FB6781AB0186A1ED474CAD6 /* StakingUnbondConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADD348E749EC6A7E3BB069DE /* StakingUnbondConfirmProtocols.swift */; }; @@ -49,6 +50,7 @@ 13CF38563E1849EAF1B4E4B6 /* ParitySignerAddConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E2CF76ABE7BC9A99724D393 /* ParitySignerAddConfirmViewFactory.swift */; }; 148748ACAE23B7D15144015B /* DAppAuthSettingsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F23EDFB699CAEEADC9263A0D /* DAppAuthSettingsViewFactory.swift */; }; 1550A6E8789263C0D734091A /* StakingUnbondSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC5083A5751A1A3CC95F4F6F /* StakingUnbondSetupWireframe.swift */; }; + 16098DABB1C9C058C1965F1D /* GovernanceUnlockSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FC9F0E50317E1583EA8E345 /* GovernanceUnlockSetupViewController.swift */; }; 1633E4E12AF8B5C16F141944 /* DAppAuthSettingsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 812BCD9B7B25BCA02E32452E /* DAppAuthSettingsInteractor.swift */; }; 163709FEE6203813261DD771 /* ReferendumVoteConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3531B386DEF40108C34E7232 /* ReferendumVoteConfirmViewLayout.swift */; }; 16FAE3C58B34D700D8A7A217 /* DAppListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E6E41F045986002E1E26C12 /* DAppListWireframe.swift */; }; @@ -155,6 +157,7 @@ 36177C077867DBAEAA2675F7 /* TransferSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D8B7BE70A9F907F8B43BFC /* TransferSetupViewController.swift */; }; 37E1E9782B9752BC50AF2476 /* YourValidatorListViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BE8644A4F6DED808248A0FE /* YourValidatorListViewFactory.swift */; }; 37E229641DCDF64AC5AF1DCD /* DAppBrowserPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF860B3465854DCBC02DFB3 /* DAppBrowserPresenter.swift */; }; + 38D0977931828C7894579968 /* GovernanceUnlockSetupInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFA54AB88E24A2053F289D74 /* GovernanceUnlockSetupInteractor.swift */; }; 39218CF5AA701518BD3B0103 /* ExportMnemonicInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200C6B2C85846AED8CA9451A /* ExportMnemonicInteractor.swift */; }; 3AD7635AFA1F7E66A3C00F56 /* ParitySignerAddressesInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF715CEF29477B59119520F1 /* ParitySignerAddressesInteractor.swift */; }; 3B6F50061AD9FC31D6712D9F /* ParaStkCollatorsSearchProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CFD9A58CDDA60D9E1204078 /* ParaStkCollatorsSearchProtocols.swift */; }; @@ -191,6 +194,7 @@ 44D9F74D7851B874F2045E7E /* LedgerInstructionsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E9691A7628B66958F8744 /* LedgerInstructionsProtocols.swift */; }; 4541F886953E046C16E42997 /* LedgerWalletConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96340EDDE0EAA7F9B6D33E96 /* LedgerWalletConfirmInteractor.swift */; }; 454D41CC5C7CC2FDAB778026 /* CreateWatchOnlyInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D9C85AB0C9D53B522DCF3C5 /* CreateWatchOnlyInteractor.swift */; }; + 46298240F3528B5C62AEC29E /* GovernanceUnlockSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 856BF961EACEB9703B2B37C7 /* GovernanceUnlockSetupWireframe.swift */; }; 47FA7B2E0D9A87E694DA9217 /* LedgerAccountConfirmationProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E4D8E59F0976D412FF0B10 /* LedgerAccountConfirmationProtocols.swift */; }; 487A912B697604FE3367FAEC /* CrowdloanYourContributionsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FDF20DCECDEA61E1BDE780B /* CrowdloanYourContributionsViewLayout.swift */; }; 488E4467895040EA85FDCC79 /* ReferendumDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B727587201B9D6F91A28428A /* ReferendumDetailsViewController.swift */; }; @@ -2230,6 +2234,7 @@ 8582395FEF296771447439FF /* AssetsSearchWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6746DDB8F277A968E6B25332 /* AssetsSearchWireframe.swift */; }; 85A093F6055DDD2E2E9253F2 /* ControllerAccountProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F829E7F8B39EE7D977001510 /* ControllerAccountProtocols.swift */; }; 86EB789787B731691B36C827 /* OnChainTransferSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1A2F7E5E278FDCC89FE097 /* OnChainTransferSetupPresenter.swift */; }; + 879D493C025963619CFADF4F /* GovernanceUnlockSetupProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4642DD5186EFA940518CCB4 /* GovernanceUnlockSetupProtocols.swift */; }; 87F7556E02F6F5BB6F1B1AEA /* ParitySignerTxQrViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A5DCA28ABF42D342BBDF9A /* ParitySignerTxQrViewLayout.swift */; }; 880059D828EEBC0200E87B9B /* SliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059D728EEBC0200E87B9B /* SliderView.swift */; }; 880059DA28EF092800E87B9B /* ThumbView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880059D928EF092800E87B9B /* ThumbView.swift */; }; @@ -2367,6 +2372,7 @@ 8EECC23DA32547DAAFC260BE /* ParaStkStakeConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9925D7FC8A58695700B4A308 /* ParaStkStakeConfirmPresenter.swift */; }; 8F131D86B269B7FAB96CF3B5 /* ParaStkYieldBoostStartWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98096689C3C8541FA585D179 /* ParaStkYieldBoostStartWireframe.swift */; }; 9081D43697D992F51E057ED2 /* CrowdloanContributionSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F7068913923A6DEEE9D8EA0 /* CrowdloanContributionSetupPresenter.swift */; }; + 9097EE6D11E2E023D2637BE5 /* GovernanceUnlockSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B9CC114CB6B28CDC59F99CF /* GovernanceUnlockSetupPresenter.swift */; }; 90A3F46EF181DC2B821CC80C /* CrowdloanContributionConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F791FE1B479CE1DF936F79F /* CrowdloanContributionConfirmViewFactory.swift */; }; 90ACE8690DA095E4F45494E9 /* TransferConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F7865BACFB8591F67D8EE06 /* TransferConfirmProtocols.swift */; }; 90EFE3768F1375470FDBE6F6 /* PurchaseViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AA3BF0C9C1E0E2C67D962F5 /* PurchaseViewFactory.swift */; }; @@ -2665,6 +2671,7 @@ E0CBD1D747361D121555FD51 /* ParaStkRedeemViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEEFB03BBA45F5143484398 /* ParaStkRedeemViewFactory.swift */; }; E14F809C3917EFA4B5388AC8 /* AccountConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A14CA4551FCC2EBD078E2242 /* AccountConfirmViewFactory.swift */; }; E221892A5B6A41A944B88336 /* ParaStkYieldBoostStartProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50829CD47D3F60E3067418B4 /* ParaStkYieldBoostStartProtocols.swift */; }; + E28F3762EAC9A4E5D21342D4 /* GovernanceUnlockSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95E4AF529B896F7E58671A74 /* GovernanceUnlockSetupViewFactory.swift */; }; E2A9BC1477D81DDDE519404C /* DAppOperationConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CECA2C5A0EFEBFDBB3C90C /* DAppOperationConfirmWireframe.swift */; }; E2F07BE11A2A6E862164C681 /* ParaStkUnstakeWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E719EB5AC6CDB97BAB5C /* ParaStkUnstakeWireframe.swift */; }; E2F3E726280823CF00CF31B5 /* ETHAccountInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F3E725280823CF00CF31B5 /* ETHAccountInjection.swift */; }; @@ -3049,6 +3056,7 @@ 2ECD8589BD30A8BE9492AD87 /* StakingRewardPayoutsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardPayoutsPresenter.swift; sourceTree = ""; }; 2F10F130391C4B3652FE8F59 /* ParitySignerTxScanProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerTxScanProtocols.swift; sourceTree = ""; }; 2F8A45125DF93218FC6C5119 /* ParaStkYourCollatorsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYourCollatorsViewFactory.swift; sourceTree = ""; }; + 2FC9F0E50317E1583EA8E345 /* GovernanceUnlockSetupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupViewController.swift; sourceTree = ""; }; 301287CBBF23EF58186A7BB5 /* DAppAuthConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthConfirmViewLayout.swift; sourceTree = ""; }; 3089A0A7C992300CE839A050 /* ParaStkYieldBoostStartPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStartPresenter.swift; sourceTree = ""; }; 30F3EC1C2DAE60DD6BB99B42 /* StakingUnbondConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondConfirmViewFactory.swift; sourceTree = ""; }; @@ -3233,6 +3241,7 @@ 7ACF32611D345B87BCE29FE0 /* DAppAddFavoriteWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAddFavoriteWireframe.swift; sourceTree = ""; }; 7B1A00299D9B50045E1A1983 /* DAppAddFavoriteProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAddFavoriteProtocols.swift; sourceTree = ""; }; 7B81B239BD9C150BFE9A82B0 /* LocksViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LocksViewFactory.swift; sourceTree = ""; }; + 7B9CC114CB6B28CDC59F99CF /* GovernanceUnlockSetupPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupPresenter.swift; sourceTree = ""; }; 7C70EBF83B2547452417E588 /* StakingRewardDetailsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardDetailsViewController.swift; sourceTree = ""; }; 7CBA1296E4C6E04EC9C5CA98 /* ParaStkUnstakePresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakePresenter.swift; sourceTree = ""; }; 7DDDB2B35CD3299F50613141 /* ReferralCrowdloanViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferralCrowdloanViewController.swift; sourceTree = ""; }; @@ -5169,6 +5178,7 @@ 84FFE504261290830054EA63 /* NetworkInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkInfoView.swift; sourceTree = ""; }; 85211D55E2AF0A697FB3EB84 /* AnalyticsRewardDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsRewardDetailsPresenter.swift; sourceTree = ""; }; 855FB8DD761E110A42435A02 /* AccountManagementWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountManagementWireframe.swift; sourceTree = ""; }; + 856BF961EACEB9703B2B37C7 /* GovernanceUnlockSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupWireframe.swift; sourceTree = ""; }; 859E0EF774DF0D498FEF8FCB /* DAppOperationConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmViewLayout.swift; sourceTree = ""; }; 85D8B7BE70A9F907F8B43BFC /* TransferSetupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TransferSetupViewController.swift; sourceTree = ""; }; 85F45A5C6145F863760F4409 /* AccountImportWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountImportWireframe.swift; sourceTree = ""; }; @@ -5326,6 +5336,7 @@ 955A6977CCE5861E4F5DCFBB /* AnalyticsValidatorsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsValidatorsViewController.swift; sourceTree = ""; }; 95A04CDB05A013ED57D3DEA3 /* LedgerAccountConfirmationViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerAccountConfirmationViewController.swift; sourceTree = ""; }; 95A60B27D3A045E0DEF23775 /* NftListViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftListViewController.swift; sourceTree = ""; }; + 95E4AF529B896F7E58671A74 /* GovernanceUnlockSetupViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupViewFactory.swift; sourceTree = ""; }; 9622C6C3102EF12BEE78D63D /* AssetSelectionViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetSelectionViewFactory.swift; sourceTree = ""; }; 96340EDDE0EAA7F9B6D33E96 /* LedgerWalletConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerWalletConfirmInteractor.swift; sourceTree = ""; }; 96BE36DA0A2310660A43FF5B /* DAppAddFavoriteInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAddFavoriteInteractor.swift; sourceTree = ""; }; @@ -5357,6 +5368,7 @@ A14CA4551FCC2EBD078E2242 /* AccountConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountConfirmViewFactory.swift; sourceTree = ""; }; A1565588CB7E044C02B091FB /* ReferendumDetailsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsViewLayout.swift; sourceTree = ""; }; A2AEC47F0599E0AC45237639 /* Pods-novawalletAll-novawallet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-novawalletAll-novawallet.release.xcconfig"; path = "Target Support Files/Pods-novawalletAll-novawallet/Pods-novawalletAll-novawallet.release.xcconfig"; sourceTree = ""; }; + A2E14458DEC3317602A17527 /* GovernanceUnlockSetupViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupViewLayout.swift; sourceTree = ""; }; A3104ABC4BECF08B0BA836AA /* AccountConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountConfirmViewController.swift; sourceTree = ""; }; A31780E84948D7FE632ECB02 /* YourValidatorListProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourValidatorListProtocols.swift; sourceTree = ""; }; A3BACB7E24BC87F9218DBBC4 /* StakingPayoutConfirmationViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPayoutConfirmationViewController.swift; sourceTree = ""; }; @@ -5563,6 +5575,7 @@ CE98454DC77EAA01301B9BBF /* ParaStkCollatorFiltersProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorFiltersProtocols.swift; sourceTree = ""; }; CF7A019F89C6CD418AEEE79C /* YourWalletsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourWalletsPresenter.swift; sourceTree = ""; }; CF891BE39D442C2D06DDF3BB /* StakingRewardDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardDetailsProtocols.swift; sourceTree = ""; }; + CFA54AB88E24A2053F289D74 /* GovernanceUnlockSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupInteractor.swift; sourceTree = ""; }; D02E38ABE379CA48E63328C4 /* DAppBrowserProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppBrowserProtocols.swift; sourceTree = ""; }; D0D4E719EB5AC6CDB97BAB5C /* ParaStkUnstakeWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeWireframe.swift; sourceTree = ""; }; D101339CC1292531CC4DB0AC /* StakingUnbondSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondSetupInteractor.swift; sourceTree = ""; }; @@ -5742,6 +5755,7 @@ F462B350260C7DBE0005AB01 /* StakingRewardHistoryTableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingRewardHistoryTableCell.swift; sourceTree = ""; }; F462B35B260C86880005AB01 /* ViewHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewHolder.swift; sourceTree = ""; }; F462B363260C88050005AB01 /* UITableView+Reuse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+Reuse.swift"; sourceTree = ""; }; + F4642DD5186EFA940518CCB4 /* GovernanceUnlockSetupProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupProtocols.swift; sourceTree = ""; }; F466AA84273D0D4200D14021 /* SettingsSectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSectionHeaderView.swift; sourceTree = ""; }; F466AA8F273D188600D14021 /* SettingsRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRow.swift; sourceTree = ""; }; F46F9F8F2733E02B00FFA556 /* MoonbeamKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoonbeamKeys.swift; sourceTree = ""; }; @@ -8700,6 +8714,7 @@ 8425D0E128FE75EA003B782A /* ReferendumVote */, CEE6BB9D4D5A0E46E857EED4 /* ReferendumVoteSetup */, B320B465EE16F566DDFE5D8C /* ReferendumVoteConfirm */, + FD4B0C614F7A70D8FB51A1C3 /* GovernanceUnlockSetup */, ); path = Governance; sourceTree = ""; @@ -13943,6 +13958,20 @@ path = ChainAddressDetails; sourceTree = ""; }; + FD4B0C614F7A70D8FB51A1C3 /* GovernanceUnlockSetup */ = { + isa = PBXGroup; + children = ( + F4642DD5186EFA940518CCB4 /* GovernanceUnlockSetupProtocols.swift */, + 856BF961EACEB9703B2B37C7 /* GovernanceUnlockSetupWireframe.swift */, + 7B9CC114CB6B28CDC59F99CF /* GovernanceUnlockSetupPresenter.swift */, + CFA54AB88E24A2053F289D74 /* GovernanceUnlockSetupInteractor.swift */, + 2FC9F0E50317E1583EA8E345 /* GovernanceUnlockSetupViewController.swift */, + A2E14458DEC3317602A17527 /* GovernanceUnlockSetupViewLayout.swift */, + 95E4AF529B896F7E58671A74 /* GovernanceUnlockSetupViewFactory.swift */, + ); + path = GovernanceUnlockSetup; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -17067,6 +17096,13 @@ B30FEC6F62918BC6F38396A2 /* ReferendumVoteConfirmViewController.swift in Sources */, 163709FEE6203813261DD771 /* ReferendumVoteConfirmViewLayout.swift in Sources */, 71533ED31DD45841CA8296A3 /* ReferendumVoteConfirmViewFactory.swift in Sources */, + 879D493C025963619CFADF4F /* GovernanceUnlockSetupProtocols.swift in Sources */, + 46298240F3528B5C62AEC29E /* GovernanceUnlockSetupWireframe.swift in Sources */, + 9097EE6D11E2E023D2637BE5 /* GovernanceUnlockSetupPresenter.swift in Sources */, + 38D0977931828C7894579968 /* GovernanceUnlockSetupInteractor.swift in Sources */, + 16098DABB1C9C058C1965F1D /* GovernanceUnlockSetupViewController.swift in Sources */, + 0E71EA5AE04940824AEA01C7 /* GovernanceUnlockSetupViewLayout.swift in Sources */, + E28F3762EAC9A4E5D21342D4 /* GovernanceUnlockSetupViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupInteractor.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupInteractor.swift new file mode 100644 index 0000000000..debe7dffe0 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupInteractor.swift @@ -0,0 +1,7 @@ +import UIKit + +final class GovernanceUnlockSetupInteractor { + weak var presenter: GovernanceUnlockSetupInteractorOutputProtocol! +} + +extension GovernanceUnlockSetupInteractor: GovernanceUnlockSetupInteractorInputProtocol {} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift new file mode 100644 index 0000000000..68c445f999 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift @@ -0,0 +1,21 @@ +import Foundation + +final class GovernanceUnlockSetupPresenter { + weak var view: GovernanceUnlockSetupViewProtocol? + let wireframe: GovernanceUnlockSetupWireframeProtocol + let interactor: GovernanceUnlockSetupInteractorInputProtocol + + init( + interactor: GovernanceUnlockSetupInteractorInputProtocol, + wireframe: GovernanceUnlockSetupWireframeProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + } +} + +extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupPresenterProtocol { + func setup() {} +} + +extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupInteractorOutputProtocol {} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift new file mode 100644 index 0000000000..81e9ce4970 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift @@ -0,0 +1,11 @@ +protocol GovernanceUnlockSetupViewProtocol: ControllerBackedProtocol {} + +protocol GovernanceUnlockSetupPresenterProtocol: AnyObject { + func setup() +} + +protocol GovernanceUnlockSetupInteractorInputProtocol: AnyObject {} + +protocol GovernanceUnlockSetupInteractorOutputProtocol: AnyObject {} + +protocol GovernanceUnlockSetupWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift new file mode 100644 index 0000000000..6203cb1fbc --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift @@ -0,0 +1,29 @@ +import UIKit + +final class GovernanceUnlockSetupViewController: UIViewController { + typealias RootViewType = GovernanceUnlockSetupViewLayout + + let presenter: GovernanceUnlockSetupPresenterProtocol + + init(presenter: GovernanceUnlockSetupPresenterProtocol) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = GovernanceUnlockSetupViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + presenter.setup() + } +} + +extension GovernanceUnlockSetupViewController: GovernanceUnlockSetupViewProtocol {} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift new file mode 100644 index 0000000000..0612416136 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift @@ -0,0 +1,17 @@ +import Foundation + +struct GovernanceUnlockSetupViewFactory { + static func createView() -> GovernanceUnlockSetupViewProtocol? { + let interactor = GovernanceUnlockSetupInteractor() + let wireframe = GovernanceUnlockSetupWireframe() + + let presenter = GovernanceUnlockSetupPresenter(interactor: interactor, wireframe: wireframe) + + let view = GovernanceUnlockSetupViewController(presenter: presenter) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewLayout.swift new file mode 100644 index 0000000000..4a277341e2 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewLayout.swift @@ -0,0 +1,13 @@ +import UIKit + +final class GovernanceUnlockSetupViewLayout: UIView { + + override init(frame: CGRect) { + super.init(frame: frame) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift new file mode 100644 index 0000000000..e3259f8a36 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class GovernanceUnlockSetupWireframe: GovernanceUnlockSetupWireframeProtocol {} \ No newline at end of file From 44e5e6bf71c3ad7b9bddb955217b0bab6df53d16 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 1 Nov 2022 11:01:59 +0500 Subject: [PATCH 139/229] fix typo --- .../Vote/Governance/Referendums/ReferendumsViewManager.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 8ec7af5438..38461aaf50 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -62,8 +62,8 @@ extension ReferendumsViewManager: UITableViewDataSource { let cell: ReferendumTableViewCell = tableView.dequeueReusableCell(for: indexPath) cell.applyStyle() - let referendumsCell = indexPath.section - 1 - let section = referendumsViewModel.sections[referendumsCell] + let referendumsSection = indexPath.section - 1 + let section = referendumsViewModel.sections[referendumsSection] switch section { case let .active(_, cellModels), let .completed(_, cellModels): let cellModel = cellModels[indexPath.row].viewModel From 33acfb928ae3590af149b33f2515a06ab289f4c5 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 2 Nov 2022 00:33:29 +0500 Subject: [PATCH 140/229] governance unlock setup --- novawallet.xcodeproj/project.pbxproj | 44 ++++ .../GovernanceUnlockInteractor.swift | 213 ++++++++++++++++++ .../GovernanceUnlockInteractorError.swift | 9 + .../GovernanceUnlockProtocols.swift | 17 ++ .../GovernanceUnlockSetupInteractor.swift | 15 +- .../GovernanceUnlockSetupPresenter.swift | 197 +++++++++++++++- .../GovernanceUnlockSetupProtocols.swift | 11 +- .../GovernanceUnlockSetupViewController.swift | 105 ++++++++- .../GovernanceUnlockSetupViewFactory.swift | 62 ++++- .../GovernanceUnlockSetupViewLayout.swift | 46 +++- .../GovernanceUnlockSetupWireframe.swift | 2 +- .../View/GovernanceUnlockTableViewCell.swift | 56 +++++ .../GovernanceUnlocksViewModel.swift | 16 ++ .../Referendums/ReferendumsInteractor.swift | 2 +- .../Referendums/ReferendumsPresenter.swift | 8 +- .../Referendums/ReferendumsProtocols.swift | 2 + .../Referendums/ReferendumsWireframe.swift | 10 + novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 19 files changed, 796 insertions(+), 21 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractorError.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/ViewModel/GovernanceUnlocksViewModel.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index a57e315e40..08f975c207 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1135,6 +1135,11 @@ 847119D5262EF95A00716580 /* PayoutInfoFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847119D4262EF95A00716580 /* PayoutInfoFactoryProtocol.swift */; }; 847119EB262EFF3800716580 /* ValidatorPayoutInfoFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847119EA262EFF3800716580 /* ValidatorPayoutInfoFactory.swift */; }; 8471538D2653B29100CB91D8 /* ChangeRewardDestinationViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8471538C2653B29100CB91D8 /* ChangeRewardDestinationViewModelFactory.swift */; }; + 8471577B2910F0AF00D7D003 /* GovernanceUnlockInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8471577A2910F0AF00D7D003 /* GovernanceUnlockInteractor.swift */; }; + 8471577D2910F18300D7D003 /* GovernanceUnlockProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8471577C2910F18300D7D003 /* GovernanceUnlockProtocols.swift */; }; + 847157802910F30500D7D003 /* GovernanceUnlockInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8471577F2910F30500D7D003 /* GovernanceUnlockInteractorError.swift */; }; + 84715783291132B400D7D003 /* GovernanceUnlockTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84715782291132B400D7D003 /* GovernanceUnlockTableViewCell.swift */; }; + 84715786291136B100D7D003 /* GovernanceUnlocksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84715785291136B100D7D003 /* GovernanceUnlocksViewModel.swift */; }; 8471825F2846A8E2002C5720 /* ActionManageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8471825E2846A8E2002C5720 /* ActionManageTableViewCell.swift */; }; 8472072E277C203A00F593DD /* UICollectionView+Reuse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8472072D277C203A00F593DD /* UICollectionView+Reuse.swift */; }; 84720730277C335000F593DD /* DAppListFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8472072F277C335000F593DD /* DAppListFlowLayout.swift */; }; @@ -4074,6 +4079,11 @@ 847119D4262EF95A00716580 /* PayoutInfoFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayoutInfoFactoryProtocol.swift; sourceTree = ""; }; 847119EA262EFF3800716580 /* ValidatorPayoutInfoFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorPayoutInfoFactory.swift; sourceTree = ""; }; 8471538C2653B29100CB91D8 /* ChangeRewardDestinationViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeRewardDestinationViewModelFactory.swift; sourceTree = ""; }; + 8471577A2910F0AF00D7D003 /* GovernanceUnlockInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockInteractor.swift; sourceTree = ""; }; + 8471577C2910F18300D7D003 /* GovernanceUnlockProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockProtocols.swift; sourceTree = ""; }; + 8471577F2910F30500D7D003 /* GovernanceUnlockInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockInteractorError.swift; sourceTree = ""; }; + 84715782291132B400D7D003 /* GovernanceUnlockTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockTableViewCell.swift; sourceTree = ""; }; + 84715785291136B100D7D003 /* GovernanceUnlocksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlocksViewModel.swift; sourceTree = ""; }; 8471825E2846A8E2002C5720 /* ActionManageTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionManageTableViewCell.swift; sourceTree = ""; }; 8472072D277C203A00F593DD /* UICollectionView+Reuse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Reuse.swift"; sourceTree = ""; }; 8472072F277C335000F593DD /* DAppListFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppListFlowLayout.swift; sourceTree = ""; }; @@ -8591,6 +8601,32 @@ path = StorageSubscription; sourceTree = ""; }; + 847157792910F06000D7D003 /* GovernanceUnlock */ = { + isa = PBXGroup; + children = ( + 8471577A2910F0AF00D7D003 /* GovernanceUnlockInteractor.swift */, + 8471577C2910F18300D7D003 /* GovernanceUnlockProtocols.swift */, + 8471577F2910F30500D7D003 /* GovernanceUnlockInteractorError.swift */, + ); + path = GovernanceUnlock; + sourceTree = ""; + }; + 847157812911321000D7D003 /* View */ = { + isa = PBXGroup; + children = ( + 84715782291132B400D7D003 /* GovernanceUnlockTableViewCell.swift */, + ); + path = View; + sourceTree = ""; + }; + 847157842911367400D7D003 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 84715785291136B100D7D003 /* GovernanceUnlocksViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; 8472974B260A9CAD009B86D0 /* Model */ = { isa = PBXGroup; children = ( @@ -8714,6 +8750,7 @@ 8425D0E128FE75EA003B782A /* ReferendumVote */, CEE6BB9D4D5A0E46E857EED4 /* ReferendumVoteSetup */, B320B465EE16F566DDFE5D8C /* ReferendumVoteConfirm */, + 847157792910F06000D7D003 /* GovernanceUnlock */, FD4B0C614F7A70D8FB51A1C3 /* GovernanceUnlockSetup */, ); path = Governance; @@ -13961,6 +13998,8 @@ FD4B0C614F7A70D8FB51A1C3 /* GovernanceUnlockSetup */ = { isa = PBXGroup; children = ( + 847157842911367400D7D003 /* ViewModel */, + 847157812911321000D7D003 /* View */, F4642DD5186EFA940518CCB4 /* GovernanceUnlockSetupProtocols.swift */, 856BF961EACEB9703B2B37C7 /* GovernanceUnlockSetupWireframe.swift */, 7B9CC114CB6B28CDC59F99CF /* GovernanceUnlockSetupPresenter.swift */, @@ -14644,6 +14683,7 @@ 889D889528F01E5B00C4320F /* ReferendumTableViewCell.swift in Sources */, F41CEB83272FF3DD00C06154 /* CrowdloanYourContributionsVMFactory.swift in Sources */, 8490146A24A9463B008F705E /* Locale+Localization.swift in Sources */, + 84715786291136B100D7D003 /* GovernanceUnlocksViewModel.swift in Sources */, 84DD5F64263DFAB700425ACF /* ErrorConditionViolation.swift in Sources */, 8428768324AE046300D91AD8 /* LanguageSelectionViewController.swift in Sources */, 8493D3E62705994200157009 /* StakingSharedState.swift in Sources */, @@ -14753,6 +14793,7 @@ 84BFFA0C288FFFA100069846 /* WalletsListViewModel.swift in Sources */, 843461CD26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift in Sources */, 88F7716428BF6B59008C028A /* GenericMultiValueView.swift in Sources */, + 847157802910F30500D7D003 /* GovernanceUnlockInteractorError.swift in Sources */, 843612BB278FD6E000DC739E /* DAppSigningType.swift in Sources */, AE2C84D525EF989A00986716 /* ValidatorInfoWireframe.swift in Sources */, F471897626C297AA006487AD /* AnalyticsValidatorsPage.swift in Sources */, @@ -15172,6 +15213,7 @@ 849013AC24A80984008F705E /* AppDelegate.swift in Sources */, 8476D39D27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift in Sources */, 8442002028E6FDBE00C49C4A /* CrowdloanListViewManager.swift in Sources */, + 8471577B2910F0AF00D7D003 /* GovernanceUnlockInteractor.swift in Sources */, 84CE69E82566750D00559427 /* ByteLengthProcessor.swift in Sources */, 8494D87A2525350000614D8F /* SubscanStatusData.swift in Sources */, 8499FEDA27BFDB8C00712589 /* NFTStreamableSource.swift in Sources */, @@ -16232,6 +16274,7 @@ 3D1FB0EF87D42F08D9250552 /* PurchasePresenter.swift in Sources */, F4F22976260DBF3F00ACFDB8 /* StakingPayoutRewardTableCell.swift in Sources */, 8428229A289BC8E400163031 /* AddAccount+ParitySignerWelcomeWireframe.swift in Sources */, + 8471577D2910F18300D7D003 /* GovernanceUnlockProtocols.swift in Sources */, 2CF2F93AF862CF54FC46B560 /* PurchaseInteractor.swift in Sources */, 90EFE3768F1375470FDBE6F6 /* PurchaseViewFactory.swift in Sources */, F452D895273D22CF008F7295 /* SettingsTableHeaderView.swift in Sources */, @@ -17020,6 +17063,7 @@ E488F3E052650FF525D41D63 /* LedgerTxConfirmInteractor.swift in Sources */, 75DAB313623E900EC475E215 /* LedgerTxConfirmViewFactory.swift in Sources */, 44D9F74D7851B874F2045E7E /* LedgerInstructionsProtocols.swift in Sources */, + 84715783291132B400D7D003 /* GovernanceUnlockTableViewCell.swift in Sources */, CD4240B756F20C338A8B3589 /* LedgerInstructionsWireframe.swift in Sources */, 91A1286763617DE022BD495F /* LedgerInstructionsPresenter.swift in Sources */, 529B87AC9E500CC2A503A859 /* LedgerInstructionsViewController.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift new file mode 100644 index 0000000000..3f4982793b --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift @@ -0,0 +1,213 @@ +import Foundation +import SubstrateSdk +import RobinHood + +class GovernanceUnlockInteractor: GovernanceUnlockInteractorInputProtocol, AnyCancellableCleaning { + weak var basePresenter: GovernanceUnlockInteractorOutputProtocol? + + let chain: ChainModel + let selectedAccount: MetaChainAccountResponse + let subscriptionFactory: GovernanceSubscriptionFactoryProtocol + let lockStateFactory: GovernanceLockStateFactoryProtocol + let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol + let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol + let blockTimeService: BlockTimeEstimationServiceProtocol + let connection: JSONRPCEngine + let runtimeProvider: RuntimeProviderProtocol + let operationQueue: OperationQueue + + private var priceProvider: AnySingleValueProvider? + private var blockNumberProvider: AnyDataProvider? + + private var blockTimeCancellable: CancellableCall? + private var unlockScheduleCancellable: CancellableCall? + + init( + chain: ChainModel, + selectedAccount: MetaChainAccountResponse, + subscriptionFactory: GovernanceSubscriptionFactoryProtocol, + lockStateFactory: GovernanceLockStateFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, + blockTimeService: BlockTimeEstimationServiceProtocol, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + operationQueue: OperationQueue + ) { + self.chain = chain + self.selectedAccount = selectedAccount + self.subscriptionFactory = subscriptionFactory + self.lockStateFactory = lockStateFactory + self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory + self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory + self.blockTimeService = blockTimeService + self.connection = connection + self.runtimeProvider = runtimeProvider + self.operationQueue = operationQueue + } + + deinit { + clearVotingSubscription() + clearCancellable() + } + + private func clearCancellable() { + clear(cancellable: &blockTimeCancellable) + clear(cancellable: &unlockScheduleCancellable) + } + + private func provideBlockTime() { + guard blockTimeCancellable == nil else { + return + } + + let operation = blockTimeService.createEstimatedBlockTimeOperation() + + operation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard operation === self?.blockTimeCancellable else { + return + } + + self?.blockTimeCancellable = nil + + do { + let blockTimeModel = try operation.extractNoCancellableResultData() + self?.basePresenter?.didReceiveBlockTime(blockTimeModel.blockTime) + } catch { + self?.basePresenter?.didReceiveBaseError(.blockTimeFetchFailed(error)) + } + } + } + + blockTimeCancellable = operation + + operationQueue.addOperation(operation) + } + + func provideUnlockSchedule(for tracksVoting: ReferendumTracksVotingDistribution, blockHash: Data?) { + clear(cancellable: &unlockScheduleCancellable) + + let wrapper = lockStateFactory.buildUnlockScheduleWrapper( + for: tracksVoting, + from: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard self?.unlockScheduleCancellable === wrapper else { + return + } + + self?.unlockScheduleCancellable = nil + + do { + let schedule = try wrapper.targetOperation.extractNoCancellableResultData() + self?.basePresenter?.didReceiveUnlockSchedule(schedule) + } catch { + self?.basePresenter?.didReceiveBaseError(.unlockScheduleFetchFailed(error)) + } + } + } + + unlockScheduleCancellable = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } + + private func clearVotingSubscription() { + subscriptionFactory.unsubscribeFromAccountVotes(self, accountId: selectedAccount.chainAccount.accountId) + } + + private func subscribeVoting() { + subscriptionFactory.subscribeToAccountVotes( + self, + accountId: selectedAccount.chainAccount.accountId + ) { [weak self] result in + switch result { + case let .success(storageResult): + self?.basePresenter?.didReceiveVoting(storageResult) + case let .failure(error): + self?.basePresenter?.didReceiveBaseError(.votingSubscriptionFailed(error)) + case .none: + self?.basePresenter?.didReceiveVoting(.init(value: nil, blockHash: nil)) + } + } + } + + private func clearAndSubscribeBlockNumber() { + blockNumberProvider?.removeObserver(self) + blockNumberProvider = nil + + blockNumberProvider = subscribeToBlockNumber(for: chain.chainId) + } + + private func clearAndSubscribePrice() { + priceProvider?.removeObserver(self) + priceProvider = nil + + if let priceId = chain.utilityAsset()?.priceId { + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } + } + + private func makeSubscriptions() { + clearAndSubscribePrice() + clearAndSubscribeBlockNumber() + + clearVotingSubscription() + subscribeVoting() + } + + func setup() { + makeSubscriptions() + } + + func refreshBlockTime() { + provideBlockTime() + } + + func refreshUnlockSchedule(for tracksVoting: ReferendumTracksVotingDistribution, blockHash: Data?) { + provideUnlockSchedule(for: tracksVoting, blockHash: blockHash) + } + + func remakeSubscriptions() { + makeSubscriptions() + } +} + +extension GovernanceUnlockInteractor: PriceLocalSubscriptionHandler, PriceLocalStorageSubscriber { + func handlePrice(result: Result, priceId _: AssetModel.PriceId) { + switch result { + case let .success(price): + basePresenter?.didReceivePrice(price) + case let .failure(error): + basePresenter?.didReceiveBaseError(.priceSubscriptionFailed(error)) + } + } +} + +extension GovernanceUnlockInteractor: GeneralLocalStorageSubscriber, GeneralLocalStorageHandler { + func handleBlockNumber(result: Result, chainId _: ChainModel.Id) { + switch result { + case let .success(blockNumber): + if let blockNumber = blockNumber { + basePresenter?.didReceiveBlockNumber(blockNumber) + } + case let .failure(error): + basePresenter?.didReceiveBaseError(.blockNumberSubscriptionFailed(error)) + } + } +} + +extension GovernanceUnlockInteractor: SelectedCurrencyDepending { + func applyCurrency() { + guard basePresenter != nil else { + return + } + + clearAndSubscribePrice() + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractorError.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractorError.swift new file mode 100644 index 0000000000..982381e356 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractorError.swift @@ -0,0 +1,9 @@ +import Foundation + +enum GovernanceUnlockInteractorError: Error { + case votingSubscriptionFailed(_ internalError: Error) + case unlockScheduleFetchFailed(_ internalError: Error) + case priceSubscriptionFailed(_ internalError: Error) + case blockNumberSubscriptionFailed(_ internalError: Error) + case blockTimeFetchFailed(_ internalError: Error) +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockProtocols.swift new file mode 100644 index 0000000000..8e07ce2681 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockProtocols.swift @@ -0,0 +1,17 @@ +import Foundation + +protocol GovernanceUnlockInteractorInputProtocol: AnyObject { + func setup() + func refreshBlockTime() + func refreshUnlockSchedule(for tracksVoting: ReferendumTracksVotingDistribution, blockHash: Data?) + func remakeSubscriptions() +} + +protocol GovernanceUnlockInteractorOutputProtocol: AnyObject { + func didReceiveVoting(_ result: CallbackStorageSubscriptionResult) + func didReceiveUnlockSchedule(_ schedule: GovernanceUnlockSchedule) + func didReceiveBlockNumber(_ block: BlockNumber) + func didReceiveBlockTime(_ time: BlockTime) + func didReceivePrice(_ price: PriceData?) + func didReceiveBaseError(_ error: GovernanceUnlockInteractorError) +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupInteractor.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupInteractor.swift index debe7dffe0..20e6e61501 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupInteractor.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupInteractor.swift @@ -1,7 +1,16 @@ import UIKit +import SubstrateSdk -final class GovernanceUnlockSetupInteractor { - weak var presenter: GovernanceUnlockSetupInteractorOutputProtocol! +final class GovernanceUnlockSetupInteractor: GovernanceUnlockInteractor { + var presenter: GovernanceUnlockSetupInteractorOutputProtocol? { + get { + basePresenter as? GovernanceUnlockSetupInteractorOutputProtocol + } + + set { + basePresenter = newValue + } + } } -extension GovernanceUnlockSetupInteractor: GovernanceUnlockSetupInteractorInputProtocol {} \ No newline at end of file +extension GovernanceUnlockSetupInteractor: GovernanceUnlockSetupInteractorInputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift index 68c445f999..f004a1b2b4 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift @@ -1,21 +1,212 @@ import Foundation +import SoraFoundation +import BigInt final class GovernanceUnlockSetupPresenter { weak var view: GovernanceUnlockSetupViewProtocol? let wireframe: GovernanceUnlockSetupWireframeProtocol let interactor: GovernanceUnlockSetupInteractorInputProtocol + let balanceViewModelFactory: BalanceViewModelFactoryProtocol + let assetDisplayInfo: AssetBalanceDisplayInfo + let logger: LoggerProtocol + + private var votingResult: CallbackStorageSubscriptionResult? + private var unlockSchedule: GovernanceUnlockSchedule? + private var blockNumber: BlockNumber? + private var blockTime: BlockTime? + private var price: PriceData? init( interactor: GovernanceUnlockSetupInteractorInputProtocol, - wireframe: GovernanceUnlockSetupWireframeProtocol + wireframe: GovernanceUnlockSetupWireframeProtocol, + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + assetDisplayInfo: AssetBalanceDisplayInfo, + logger: LoggerProtocol, + localizationManager: LocalizationManagerProtocol ) { self.interactor = interactor self.wireframe = wireframe + self.balanceViewModelFactory = balanceViewModelFactory + self.assetDisplayInfo = assetDisplayInfo + self.logger = logger + self.localizationManager = localizationManager + } + + private func createTotalBalanceViewModel(for amount: BigUInt) -> BalanceViewModelProtocol { + let decimalAmount = Decimal.fromSubstrateAmount(amount, precision: assetDisplayInfo.assetPrecision) ?? 0 + return balanceViewModelFactory.balanceFromPrice(decimalAmount, priceData: price).value(for: selectedLocale) + } + + private func createUnlockClaimState( + for unlockAt: BlockNumber, + block: BlockNumber, + blockTime: BlockTime + ) -> GovernanceUnlocksViewModel.ClaimState { + if block < unlockAt { + let remainedTimeInSeconds = block.secondsTo(block: unlockAt, blockDuration: blockTime) + + if let leftTime = remainedTimeInSeconds.localizedDaysOrTime(for: selectedLocale) { + let time = R.string.localizable.commonTimeLeftFormat( + leftTime, + preferredLanguages: selectedLocale.rLanguages + ) + + return .afterPeriod(time: time) + } else { + return .afterPeriod(time: "") + } + + } else { + return .now + } + } + + private func createClaimableViewModel(for amount: BigUInt) -> GovernanceUnlocksViewModel.Item { + let amountDecimal = Decimal.fromSubstrateAmount( + amount, + precision: assetDisplayInfo.assetPrecision + ) ?? 0 + + let amountString = balanceViewModelFactory.amountFromValue(amountDecimal).value(for: selectedLocale) + + return .init(amount: amountString, claimState: .now) + } + + private func createUnlockViewModel( + for amount: BigUInt, + unlockAt: BlockNumber, + block: BlockNumber, + blockTime: BlockTime + ) -> GovernanceUnlocksViewModel.Item { + let amountDecimal = Decimal.fromSubstrateAmount( + amount, + precision: assetDisplayInfo.assetPrecision + ) ?? 0 + + let amountString = balanceViewModelFactory.amountFromValue(amountDecimal).value(for: selectedLocale) + + let claimState = createUnlockClaimState(for: unlockAt, block: block, blockTime: blockTime) + + return .init(amount: amountString, claimState: claimState) + } + + private func updateView() { + guard + let blockNumber = blockNumber, + let blockTime = blockTime, + let tracksVoting = votingResult?.value else { + return + } + + let totalViewModel = createTotalBalanceViewModel(for: tracksVoting.totalLocked()) + + let items: [GovernanceUnlocksViewModel.Item] + + if let unlockSchedule = unlockSchedule { + let availableUnlock = unlockSchedule.availableUnlock(at: blockNumber) + + let remainingUnlocks = unlockSchedule.remainingLocks(after: blockNumber) + + let remainingUnlockViewModels = remainingUnlocks.map { + createUnlockViewModel( + for: $0.amount, + unlockAt: $0.unlockAt, + block: blockNumber, + blockTime: blockTime + ) + } + + if !availableUnlock.isEmpty { + let availableUnlockViewModel = createClaimableViewModel(for: availableUnlock.amount) + items = [availableUnlockViewModel] + remainingUnlockViewModels + } else { + items = remainingUnlockViewModels + } + } else { + items = [] + } + + view?.didReceive(viewModel: .init(total: totalViewModel, items: items)) + } + + private func refreshUnlockSchedule() { + guard let tracksVoting = votingResult?.value else { + return + } + + interactor.refreshUnlockSchedule(for: tracksVoting, blockHash: nil) } } extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupPresenterProtocol { - func setup() {} + func setup() { + interactor.setup() + } + + func unlock() {} } -extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupInteractorOutputProtocol {} \ No newline at end of file +extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupInteractorOutputProtocol { + func didReceiveVoting(_ result: CallbackStorageSubscriptionResult) { + votingResult = result + + updateView() + + if let tracksVoting = result.value { + interactor.refreshUnlockSchedule(for: tracksVoting, blockHash: result.blockHash) + } + } + + func didReceiveUnlockSchedule(_ schedule: GovernanceUnlockSchedule) { + unlockSchedule = schedule + + updateView() + } + + func didReceiveBlockNumber(_ block: BlockNumber) { + blockNumber = block + + updateView() + + interactor.refreshBlockTime() + } + + func didReceiveBlockTime(_ time: BlockTime) { + blockTime = time + + updateView() + } + + func didReceivePrice(_ price: PriceData?) { + self.price = price + + updateView() + } + + func didReceiveBaseError(_ error: GovernanceUnlockInteractorError) { + logger.error("Did receive error: \(error)") + + switch error { + case .votingSubscriptionFailed, .priceSubscriptionFailed, .blockNumberSubscriptionFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + case .unlockScheduleFetchFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.refreshUnlockSchedule() + } + case .blockTimeFetchFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.refreshBlockTime() + } + } + } +} + +extension GovernanceUnlockSetupPresenter: Localizable { + func applyLocalization() { + if let view = view, view.isSetup { + updateView() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift index 81e9ce4970..f820d59c7b 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift @@ -1,11 +1,14 @@ -protocol GovernanceUnlockSetupViewProtocol: ControllerBackedProtocol {} +protocol GovernanceUnlockSetupViewProtocol: ControllerBackedProtocol { + func didReceive(viewModel: GovernanceUnlocksViewModel) +} protocol GovernanceUnlockSetupPresenterProtocol: AnyObject { func setup() + func unlock() } -protocol GovernanceUnlockSetupInteractorInputProtocol: AnyObject {} +protocol GovernanceUnlockSetupInteractorInputProtocol: GovernanceUnlockInteractorInputProtocol {} -protocol GovernanceUnlockSetupInteractorOutputProtocol: AnyObject {} +protocol GovernanceUnlockSetupInteractorOutputProtocol: GovernanceUnlockInteractorOutputProtocol {} -protocol GovernanceUnlockSetupWireframeProtocol: AnyObject {} +protocol GovernanceUnlockSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable {} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift index 6203cb1fbc..6b1f573bd9 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift @@ -1,10 +1,13 @@ import UIKit +import SoraFoundation -final class GovernanceUnlockSetupViewController: UIViewController { +final class GovernanceUnlockSetupViewController: UIViewController, ViewHolder { typealias RootViewType = GovernanceUnlockSetupViewLayout let presenter: GovernanceUnlockSetupPresenterProtocol + private var viewModel: GovernanceUnlocksViewModel? + init(presenter: GovernanceUnlockSetupPresenterProtocol) { self.presenter = presenter super.init(nibName: nil, bundle: nil) @@ -22,8 +25,106 @@ final class GovernanceUnlockSetupViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + setupLocalization() + setupTableView() + setupHandlers() + presenter.setup() } + + private func setupTableView() { + rootView.tableView.registerClassForCell(GovernanceUnlockTableViewCell.self) + rootView.tableView.registerClassForCell(CrowdloanYourContributionsTotalCell.self) + + rootView.tableView.dataSource = self + } + + private func setupHandlers() { + rootView.unlockButton.addTarget( + self, + action: #selector(actionUnlock), + for: .touchUpInside + ) + } + + private func setupLocalization() { + title = R.string.localizable.walletBalanceLocked(preferredLanguages: selectedLocale.rLanguages) + + rootView.unlockButton.imageWithTitleView?.title = R.string.localizable.commonUnlock( + preferredLanguages: selectedLocale.rLanguages + ) + rootView.unlockButton.invalidateLayout() + } + + @objc private func actionUnlock() { + presenter.unlock() + } +} + +extension GovernanceUnlockSetupViewController: UITableViewDataSource { + func numberOfSections(in _: UITableView) -> Int { + viewModel != nil ? 2 : 0 + } + + func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { + guard let viewModel = viewModel else { + return 0 + } + + if section == 0 { + return 1 + } else { + return viewModel.items.count + } + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + if indexPath.section == 0 { + let cell = tableView.dequeueReusableCellWithType( + CrowdloanYourContributionsTotalCell.self, + forIndexPath: indexPath + ) + + cell.view.apply(style: .readonly) + cell.view.bind( + model: .init( + title: R.string.localizable.crowdloanYouContributionsTotal( + preferredLanguages: selectedLocale.rLanguages + ), + count: nil, + amount: viewModel?.total.amount ?? "", + amountDetails: viewModel?.total.price ?? "" + ) + ) + + return cell + } else { + let cell = tableView.dequeueReusableCellWithType( + GovernanceUnlockTableViewCell.self, + forIndexPath: indexPath + ) + + if let viewModel = viewModel { + cell.bind(viewModel: viewModel.items[indexPath.row], locale: selectedLocale) + } + + return cell + } + } } -extension GovernanceUnlockSetupViewController: GovernanceUnlockSetupViewProtocol {} \ No newline at end of file +extension GovernanceUnlockSetupViewController: GovernanceUnlockSetupViewProtocol { + func didReceive(viewModel: GovernanceUnlocksViewModel) { + self.viewModel = viewModel + + rootView.tableView.reloadData() + } +} + +extension GovernanceUnlockSetupViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + setupLocalization() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift index 0612416136..4d3f88343f 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift @@ -1,11 +1,30 @@ import Foundation +import SoraFoundation struct GovernanceUnlockSetupViewFactory { - static func createView() -> GovernanceUnlockSetupViewProtocol? { - let interactor = GovernanceUnlockSetupInteractor() + static func createView(for state: GovernanceSharedState) -> GovernanceUnlockSetupViewProtocol? { + guard + let interactor = createInteractor(for: state), + let assetInfo = state.settings.value?.utilityAssetDisplayInfo(), + let currencyManager = CurrencyManager.shared else { + return nil + } + let wireframe = GovernanceUnlockSetupWireframe() - let presenter = GovernanceUnlockSetupPresenter(interactor: interactor, wireframe: wireframe) + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: assetInfo, + priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) + ) + + let presenter = GovernanceUnlockSetupPresenter( + interactor: interactor, + wireframe: wireframe, + balanceViewModelFactory: balanceViewModelFactory, + assetDisplayInfo: assetInfo, + logger: Logger.shared, + localizationManager: LocalizationManager.shared + ) let view = GovernanceUnlockSetupViewController(presenter: presenter) @@ -14,4 +33,39 @@ struct GovernanceUnlockSetupViewFactory { return view } -} \ No newline at end of file + + private static func createInteractor(for state: GovernanceSharedState) -> GovernanceUnlockSetupInteractor? { + guard + let wallet = SelectedWalletSettings.shared.value, + let chain = state.settings.value, + let selectedAccount = wallet.fetchMetaChainAccount(for: chain.accountRequest()) else { + return nil + } + + guard + let connection = state.chainRegistry.getConnection(for: chain.chainId), + let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId), + let subscriptionFactory = state.subscriptionFactory, + let blockTimeService = state.blockTimeService else { + return nil + } + + let lockStateFactory = Gov2LockStateFactory( + requestFactory: state.requestFactory, + unlocksCalculator: Gov2UnlocksCalculator() + ) + + return .init( + chain: chain, + selectedAccount: selectedAccount, + subscriptionFactory: subscriptionFactory, + lockStateFactory: lockStateFactory, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, + blockTimeService: blockTimeService, + connection: connection, + runtimeProvider: runtimeProvider, + operationQueue: OperationManagerFacade.sharedDefaultQueue + ) + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewLayout.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewLayout.swift index 4a277341e2..ebf8d4089c 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewLayout.swift @@ -1,13 +1,57 @@ import UIKit final class GovernanceUnlockSetupViewLayout: UIView { + let tableView: UITableView = { + let tableView = UITableView() + tableView.backgroundColor = .clear + tableView.separatorStyle = .none + tableView.allowsSelection = false + return tableView + }() + + let unlockButton: TriangularedButton = { + let button = TriangularedButton() + button.applyDefaultStyle() + return button + }() override init(frame: CGRect) { super.init(frame: frame) + + backgroundColor = R.color.colorBlack() + + setupLayout() } @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } -} \ No newline at end of file + + override func layoutSubviews() { + super.layoutSubviews() + + let bottomInset = abs(distanceBetween(bottomOf: self, andTopOf: unlockButton)) + 16.0 + tableView.contentInset = .init(top: 0, left: 0, bottom: bottomInset, right: 0) + } + + private func distanceBetween(bottomOf view1: UIView, andTopOf view2: UIView) -> CGFloat { + let frame2 = view1.convert(view2.bounds, from: view2) + return frame2.minY - view1.bounds.maxY + } + + private func setupLayout() { + addSubview(tableView) + tableView.snp.makeConstraints { make in + make.top.equalTo(safeAreaLayoutGuide) + make.leading.bottom.trailing.equalToSuperview() + } + + addSubview(unlockButton) + unlockButton.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(UIConstants.horizontalInset) + make.bottom.equalTo(safeAreaLayoutGuide).inset(UIConstants.actionBottomInset) + make.height.equalTo(UIConstants.actionHeight) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift index e3259f8a36..42edfea76d 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift @@ -1,3 +1,3 @@ import Foundation -final class GovernanceUnlockSetupWireframe: GovernanceUnlockSetupWireframeProtocol {} \ No newline at end of file +final class GovernanceUnlockSetupWireframe: GovernanceUnlockSetupWireframeProtocol {} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift new file mode 100644 index 0000000000..6d107fcd79 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift @@ -0,0 +1,56 @@ +import UIKit + +final class GovernanceUnlockTableViewCell: UITableViewCell { + private let lockView = GenericTitleValueView() + + var amountLabel: UILabel { lockView.titleView } + var detailsLabel: UILabel { lockView.valueView.detailsLabel } + var iconImageView: UIImageView { lockView.valueView.imageView } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + setupLayout() + applyStyle() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func bind(viewModel: GovernanceUnlocksViewModel.Item, locale: Locale) { + amountLabel.text = viewModel.amount + + switch viewModel.claimState { + case let .afterPeriod(time): + lockView.valueView.hidesIcon = false + detailsLabel.textColor = R.color.colorTransparentText() + detailsLabel.text = time + case .now: + lockView.valueView.hidesIcon = true + detailsLabel.textColor = R.color.colorGreen() + detailsLabel.text = R.string.localizable.commonUnlockable(preferredLanguages: locale.rLanguages) + } + } + + private func applyStyle() { + backgroundColor = .clear + + amountLabel.apply(style: .regularSubhedlineWhite) + + detailsLabel.font = .caption1 + detailsLabel.numberOfLines = 1 + lockView.valueView.spacing = 4 + iconImageView.image = R.image.iconPending() + } + + private func setupLayout() { + addSubview(lockView) + lockView.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(UIConstants.horizontalInset) + make.top.bottom.equalToSuperview() + make.height.equalTo(40) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/ViewModel/GovernanceUnlocksViewModel.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/ViewModel/GovernanceUnlocksViewModel.swift new file mode 100644 index 0000000000..18ceb0f4f6 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/ViewModel/GovernanceUnlocksViewModel.swift @@ -0,0 +1,16 @@ +import Foundation + +struct GovernanceUnlocksViewModel { + enum ClaimState { + case now + case afterPeriod(time: String) + } + + struct Item { + let amount: String + let claimState: ClaimState + } + + let total: BalanceViewModelProtocol + let items: [Item] +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 7f8bc8f43e..82c646c8c5 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -347,7 +347,7 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { func refreshUnlockSchedule(for tracksVoting: ReferendumTracksVotingDistribution, blockHash: Data?) { if let chain = governanceState.settings.value { - clear(cancellable: &referendumsCancellable) + clear(cancellable: &unlockScheduleCancellable) guard let connection = chainRegistry.getConnection(for: chain.chainId) else { presenter?.didReceiveError(.unlockScheduleFetchFailed(ChainRegistryError.connectionUnavailable)) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 7d19ee7f3c..ef966b81e6 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -266,7 +266,9 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { ) } - func selectUnlocks() {} + func selectUnlocks() { + wireframe.showUnlocksDetails(from: view) + } } extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { @@ -275,7 +277,9 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { updateReferendumsView() updateUnlocksView() - refreshUnlockSchedule() + if let tracksVoting = voting.value { + interactor.refreshUnlockSchedule(for: tracksVoting, blockHash: voting.blockHash) + } } func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 439dbc0b0b..031cee8349 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -51,4 +51,6 @@ protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, Commo accountVotes: ReferendumAccountVoteLocal?, metadata: ReferendumMetadataLocal? ) + + func showUnlocksDetails(from view: ControllerBackedProtocol?) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index c38fcdb88d..10f83ba343 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -51,4 +51,14 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { view?.controller.navigationController?.pushViewController(detailsView.controller, animated: true) } + + func showUnlocksDetails(from view: ControllerBackedProtocol?) { + guard let unlocksView = GovernanceUnlockSetupViewFactory.createView(for: state) else { + return + } + + let navigationController = ImportantFlowViewFactory.createNavigation(from: unlocksView.controller) + + view?.controller.present(navigationController, animated: true) + } } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 534c7d434c..f5e66f29aa 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1074,3 +1074,4 @@ "gov.unknown" = "Unknown"; "gov.in.queue.counter" = "(%@ of %@)"; "common.unlock" = "Unlock"; +"common.unlockable" = "Unlockable"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index b811646a91..850ec503dc 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1075,3 +1075,4 @@ "gov.unknown" = "Неизвестно"; "gov.in.queue.counter" = "(%@ из %@)"; "common.unlock" = "Разблокировать"; +"common.unlockable" = "Разблокируемые"; From 025a57d1767ad8f630d61b13e5aecba2de68e527 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 2 Nov 2022 10:44:05 +0500 Subject: [PATCH 141/229] refactor unlocks --- .../GovernanceUnlockSetupViewController.swift | 4 +++- .../GovernanceUnlockSetupViewFactory.swift | 4 +++- .../View/GovernanceUnlockTableViewCell.swift | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift index 6b1f573bd9..e9157192ad 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift @@ -8,9 +8,11 @@ final class GovernanceUnlockSetupViewController: UIViewController, ViewHolder { private var viewModel: GovernanceUnlocksViewModel? - init(presenter: GovernanceUnlockSetupPresenterProtocol) { + init(presenter: GovernanceUnlockSetupPresenterProtocol, localizationManager: LocalizationManagerProtocol) { self.presenter = presenter super.init(nibName: nil, bundle: nil) + + self.localizationManager = localizationManager } @available(*, unavailable) diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift index 4d3f88343f..9456ca8407 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift @@ -17,6 +17,8 @@ struct GovernanceUnlockSetupViewFactory { priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) ) + let localizationManager = LocalizationManager.shared + let presenter = GovernanceUnlockSetupPresenter( interactor: interactor, wireframe: wireframe, @@ -26,7 +28,7 @@ struct GovernanceUnlockSetupViewFactory { localizationManager: LocalizationManager.shared ) - let view = GovernanceUnlockSetupViewController(presenter: presenter) + let view = GovernanceUnlockSetupViewController(presenter: presenter, localizationManager: localizationManager) presenter.view = view interactor.presenter = presenter diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift index 6d107fcd79..d02872dbc4 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift @@ -43,6 +43,8 @@ final class GovernanceUnlockTableViewCell: UITableViewCell { detailsLabel.numberOfLines = 1 lockView.valueView.spacing = 4 iconImageView.image = R.image.iconPending() + + lockView.valueView.mode = .detailsIcon } private func setupLayout() { From 23f0039898a24f070cab621d89e05fae17380f5e Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 2 Nov 2022 11:48:21 +0500 Subject: [PATCH 142/229] add timer --- .../GovernanceUnlockSetupPresenter.swift | 124 +++++++++++++++++- .../GovernanceUnlockSetupProtocols.swift | 1 + .../GovernanceUnlockSetupViewController.swift | 30 +++++ .../View/GovernanceUnlockTableViewCell.swift | 6 +- .../ReferendumDetailsPresenter.swift | 4 - 5 files changed, 157 insertions(+), 8 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift index f004a1b2b4..a4a6845609 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift @@ -16,6 +16,9 @@ final class GovernanceUnlockSetupPresenter { private var blockTime: BlockTime? private var price: PriceData? + private var maxStatusTimeInterval: TimeInterval? + private var countdownTimer: CountdownTimer? + init( interactor: GovernanceUnlockSetupInteractorInputProtocol, wireframe: GovernanceUnlockSetupWireframeProtocol, @@ -32,20 +35,49 @@ final class GovernanceUnlockSetupPresenter { self.localizationManager = localizationManager } + deinit { + invalidateTimer() + } + private func createTotalBalanceViewModel(for amount: BigUInt) -> BalanceViewModelProtocol { let decimalAmount = Decimal.fromSubstrateAmount(amount, precision: assetDisplayInfo.assetPrecision) ?? 0 return balanceViewModelFactory.balanceFromPrice(decimalAmount, priceData: price).value(for: selectedLocale) } + private func calculateMaxUnlockTimeInterval( + block: BlockNumber, + blockTime: BlockTime + ) -> TimeInterval? { + let intervals: [TimeInterval] = (unlockSchedule?.items ?? []).compactMap { item in + if block < item.unlockAt { + return block.secondsTo(block: item.unlockAt, blockDuration: blockTime) + } else { + return nil + } + } + + return intervals.max() + } + private func createUnlockClaimState( for unlockAt: BlockNumber, block: BlockNumber, - blockTime: BlockTime + blockTime: BlockTime, + elapsedTimeInterval: TimeInterval? ) -> GovernanceUnlocksViewModel.ClaimState { if block < unlockAt { let remainedTimeInSeconds = block.secondsTo(block: unlockAt, blockDuration: blockTime) - if let leftTime = remainedTimeInSeconds.localizedDaysOrTime(for: selectedLocale) { + let tickedTime: TimeInterval + + if let elapsedTimeInterval = elapsedTimeInterval { + tickedTime = remainedTimeInSeconds > elapsedTimeInterval ? + remainedTimeInSeconds - elapsedTimeInterval : 0 + } else { + tickedTime = remainedTimeInSeconds + } + + if let leftTime = tickedTime.localizedDaysOrTime(for: selectedLocale) { let time = R.string.localizable.commonTimeLeftFormat( leftTime, preferredLanguages: selectedLocale.rLanguages @@ -85,7 +117,12 @@ final class GovernanceUnlockSetupPresenter { let amountString = balanceViewModelFactory.amountFromValue(amountDecimal).value(for: selectedLocale) - let claimState = createUnlockClaimState(for: unlockAt, block: block, blockTime: blockTime) + let claimState = createUnlockClaimState( + for: unlockAt, + block: block, + blockTime: blockTime, + elapsedTimeInterval: nil + ) return .init(amount: amountString, claimState: claimState) } @@ -136,6 +173,69 @@ final class GovernanceUnlockSetupPresenter { interactor.refreshUnlockSchedule(for: tracksVoting, blockHash: nil) } + + private func invalidateTimer() { + countdownTimer?.delegate = self + countdownTimer?.stop() + countdownTimer = nil + } + + private func setupTimerIfNeeded() { + invalidateTimer() + + guard + let blockNumber = blockNumber, + let blockTime = blockTime else { + return + } + + guard let maxTimeInterval = calculateMaxUnlockTimeInterval(block: blockNumber, blockTime: blockTime) else { + return + } + + maxStatusTimeInterval = maxTimeInterval + + countdownTimer = CountdownTimer() + countdownTimer?.delegate = self + countdownTimer?.start(with: maxTimeInterval) + } + + private func updateViewOnTimerTick() { + guard + let maxStatusTimeInterval = maxStatusTimeInterval, + let remainedInterval = countdownTimer?.remainedInterval, + let blockNumber = blockNumber, + let blockTime = blockTime else { + return + } + + let elapsedTimeInterval = maxStatusTimeInterval - remainedInterval + + let items: [GovernanceUnlocksViewModel.ClaimState] + + if let unlockSchedule = unlockSchedule { + let availableUnlock = unlockSchedule.availableUnlock(at: blockNumber) + + let remainingUnlocks = unlockSchedule.remainingLocks(after: blockNumber).map { + createUnlockClaimState( + for: $0.unlockAt, + block: blockNumber, + blockTime: blockTime, + elapsedTimeInterval: elapsedTimeInterval + ) + } + + if !availableUnlock.isEmpty { + items = [.now] + remainingUnlocks + } else { + items = remainingUnlocks + } + } else { + items = [] + } + + view?.didTickClaim(states: items) + } } extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupPresenterProtocol { @@ -169,12 +269,16 @@ extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupInteractorOutputP updateView() interactor.refreshBlockTime() + + refreshUnlockSchedule() } func didReceiveBlockTime(_ time: BlockTime) { blockTime = time updateView() + + setupTimerIfNeeded() } func didReceivePrice(_ price: PriceData?) { @@ -203,6 +307,20 @@ extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupInteractorOutputP } } +extension GovernanceUnlockSetupPresenter: CountdownTimerDelegate { + func didStart(with _: TimeInterval) { + updateViewOnTimerTick() + } + + func didCountdown(remainedInterval _: TimeInterval) { + updateViewOnTimerTick() + } + + func didStop(with _: TimeInterval) { + updateViewOnTimerTick() + } +} + extension GovernanceUnlockSetupPresenter: Localizable { func applyLocalization() { if let view = view, view.isSetup { diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift index f820d59c7b..936487f818 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift @@ -1,5 +1,6 @@ protocol GovernanceUnlockSetupViewProtocol: ControllerBackedProtocol { func didReceive(viewModel: GovernanceUnlocksViewModel) + func didTickClaim(states: [GovernanceUnlocksViewModel.ClaimState]) } protocol GovernanceUnlockSetupPresenterProtocol: AnyObject { diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift index e9157192ad..f282bcd496 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift @@ -113,6 +113,22 @@ extension GovernanceUnlockSetupViewController: UITableViewDataSource { return cell } } + + private func applyClaimStates() { + guard let items = viewModel?.items else { + return + } + + let visibleIndexPaths = rootView.tableView.indexPathsForVisibleRows?.filter { $0.section > 0 } ?? [] + + visibleIndexPaths.forEach { indexPath in + guard let cell = rootView.tableView.cellForRow(at: indexPath) as? GovernanceUnlockTableViewCell else { + return + } + + cell.bind(claimState: items[indexPath.row].claimState, locale: selectedLocale) + } + } } extension GovernanceUnlockSetupViewController: GovernanceUnlockSetupViewProtocol { @@ -121,6 +137,20 @@ extension GovernanceUnlockSetupViewController: GovernanceUnlockSetupViewProtocol rootView.tableView.reloadData() } + + func didTickClaim(states: [GovernanceUnlocksViewModel.ClaimState]) { + guard let viewModel = viewModel else { + return + } + + let newItems = zip(states, viewModel.items).map { + GovernanceUnlocksViewModel.Item(amount: $0.1.amount, claimState: $0.0) + } + + self.viewModel = .init(total: viewModel.total, items: newItems) + + applyClaimStates() + } } extension GovernanceUnlockSetupViewController: Localizable { diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift index d02872dbc4..138c8c5897 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/View/GovernanceUnlockTableViewCell.swift @@ -22,7 +22,11 @@ final class GovernanceUnlockTableViewCell: UITableViewCell { func bind(viewModel: GovernanceUnlocksViewModel.Item, locale: Locale) { amountLabel.text = viewModel.amount - switch viewModel.claimState { + bind(claimState: viewModel.claimState, locale: locale) + } + + func bind(claimState: GovernanceUnlocksViewModel.ClaimState, locale: Locale) { + switch claimState { case let .afterPeriod(time): lockView.valueView.hidesIcon = false detailsLabel.textColor = R.color.colorTransparentText() diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 613cc1237f..378ae43a10 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -290,10 +290,6 @@ final class ReferendumDetailsPresenter { return } - guard maxStatusTimeInterval != timeInterval else { - return - } - maxStatusTimeInterval = timeInterval statusViewModel = activeTimeModel From 93c411f93871e87b68ea1b962ad298c471394135 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 2 Nov 2022 11:51:46 +0500 Subject: [PATCH 143/229] has unlocks state --- .../GovernanceUnlockSetupViewController.swift | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift index f282bcd496..687a99936a 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewController.swift @@ -30,6 +30,7 @@ final class GovernanceUnlockSetupViewController: UIViewController, ViewHolder { setupLocalization() setupTableView() setupHandlers() + updateUnlockState() presenter.setup() } @@ -58,6 +59,25 @@ final class GovernanceUnlockSetupViewController: UIViewController, ViewHolder { rootView.unlockButton.invalidateLayout() } + private func updateUnlockState() { + let hasUnlockable = viewModel?.items.contains { + switch $0.claimState { + case .now: + return true + case .afterPeriod: + return false + } + } ?? false + + if hasUnlockable { + rootView.unlockButton.applyEnabledStyle() + } else { + rootView.unlockButton.applyDisabledStyle() + } + + rootView.unlockButton.isUserInteractionEnabled = hasUnlockable + } + @objc private func actionUnlock() { presenter.unlock() } @@ -136,6 +156,8 @@ extension GovernanceUnlockSetupViewController: GovernanceUnlockSetupViewProtocol self.viewModel = viewModel rootView.tableView.reloadData() + + updateUnlockState() } func didTickClaim(states: [GovernanceUnlocksViewModel.ClaimState]) { @@ -150,6 +172,7 @@ extension GovernanceUnlockSetupViewController: GovernanceUnlockSetupViewProtocol self.viewModel = .init(total: viewModel.total, items: newItems) applyClaimStates() + updateUnlockState() } } From dfd7e641aa5eb3aecc0b2903942964c57e87cb59 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 2 Nov 2022 12:11:25 +0500 Subject: [PATCH 144/229] fix max unlock period --- .../Governance/Operation/Locks/Gov2LockStateFactory.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift index 6c1fc278ed..bdade09a63 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift @@ -116,12 +116,12 @@ final class Gov2LockStateFactory { func calculatePriorLockMax(from trackVotes: ReferendumTracksVotingDistribution) -> BlockNumber? { let optCastingMax = trackVotes.votes.priorLocks.values - .filter { $0.amount > 0 } + .filter { $0.exists } .map(\.unlockAt) .max() let optDelegatingMax = trackVotes.votes.delegatings.values - .compactMap { $0.prior.amount > 0 ? $0.prior.unlockAt : nil } + .compactMap { $0.prior.exists ? $0.prior.unlockAt : nil } .max() if let castingMax = optCastingMax, let delegatingMax = optDelegatingMax { @@ -143,7 +143,7 @@ final class Gov2LockStateFactory { let referendum = referendumKeyValue.value let accountVoting = trackVotes.votes - guard let vote = accountVoting.votes[referendumIndex], vote.totalBalance > 0 else { + guard let vote = accountVoting.votes[referendumIndex] else { return nil } @@ -201,9 +201,7 @@ final class Gov2LockStateFactory { let newPeriod: Moment? - // if amount is zero we don't take into account the vote for the referendum if - newVote.voteAction.amount > 0, let referendum = referendums[newVote.index], let periodWithNewVote = try? self.unlocksCalculator.estimateVoteLockingPeriod( for: referendum, From 541998b0dcc9c33e3bde2c88109cf0e70bd7615a Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 2 Nov 2022 13:50:36 +0500 Subject: [PATCH 145/229] fix waiting status --- .../ReferendumStatusViewModelFactory.swift | 12 +----------- .../ViewModel/ReferendumsModelFactory.swift | 18 +++++++++++------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift index 7a6eb13978..b21adb8cae 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift @@ -113,17 +113,7 @@ extension ReferendumStatusViewModelFactory: ReferendumStatusViewModelFactoryProt let strings = R.string.localizable.self switch referendum.state { case let .preparing(model): - if model.deposit == nil { - let title = strings.governanceReferendumsTimeWaitingDeposit(preferredLanguages: locale.rLanguages) - let timeViewModel = ReferendumInfoView.Time( - titleIcon: .init(title: title, icon: R.image.iconLightPending()), - isUrgent: false - ) - - return StatusTimeViewModel(viewModel: timeViewModel, timeInterval: nil) { _ in - timeViewModel - } - } else if currentBlock >= model.preparingEnd { + if model.deposit == nil || currentBlock >= model.preparingEnd { return createTimeViewModel( state: referendum.state, atBlock: max(currentBlock, model.timeoutAt), diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 379bfcabdf..131d46beaf 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -123,6 +123,16 @@ final class ReferendumsModelFactory { } } + private func createPreparingStatus(for model: ReferendumStateLocal.Preparing, locale: Locale) -> String { + if model.inQueue { + return createInQueueFormatting(for: model.inQueuePosition, locale: locale) + } else if model.deposit == nil { + return Strings.governanceReferendumsTimeWaitingDeposit(preferredLanguages: locale.rLanguages) + } else { + return Strings.governanceReferendumsStatusPreparing(preferredLanguages: locale.rLanguages) + } + } + private func providePreparingReferendumCellViewModel( _ model: ReferendumStateLocal.Preparing, params: StatusParams, @@ -135,13 +145,7 @@ final class ReferendumsModelFactory { locale: locale ) - let title: String - - if model.inQueue { - title = createInQueueFormatting(for: model.inQueuePosition, locale: locale) - } else { - title = Strings.governanceReferendumsStatusPreparing(preferredLanguages: locale.rLanguages) - } + let title = createPreparingStatus(for: model, locale: locale) switch model.voting { case let .supportAndVotes(supportAndVotes): From c8d26caab532a400ca920f04075f0f77002612b1 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 2 Nov 2022 17:04:13 +0500 Subject: [PATCH 146/229] interactor add --- novawallet.xcodeproj/project.pbxproj | 58 ++++++- .../ConvictionVoting+Call.swift | 46 ++++++ .../ConvictionVoting+Call.swift | 18 --- .../GovernanceUnlockConfirmInteractor.swift | 145 ++++++++++++++++++ .../GovernanceUnlockConfirmPresenter.swift | 21 +++ .../GovernanceUnlockConfirmProtocols.swift | 23 +++ ...overnanceUnlockConfirmViewController.swift | 29 ++++ .../GovernanceUnlockConfirmViewFactory.swift | 17 ++ .../GovernanceUnlockConfirmViewLayout.swift | 13 ++ .../GovernanceUnlockConfirmWireframe.swift | 3 + ...vernanceUnlockConfirmInteractorError.swift | 7 + .../Operation/Gov2ExtrinsicFactory.swift | 41 +++++ .../GovernanceExtrinsicFactoryProtocol.swift | 6 + 13 files changed, 408 insertions(+), 19 deletions(-) create mode 100644 novawallet/Common/Substrate/Calls/ConvictionVoting/ConvictionVoting+Call.swift delete mode 100644 novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+Call.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmWireframe.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInteractorError.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 5c06921b7b..5e8ea45880 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -76,6 +76,7 @@ 21B297239CC294307EF20B58 /* ParaStkYieldBoostSetupInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78A5A3C9077FCE262224B832 /* ParaStkYieldBoostSetupInteractor.swift */; }; 22403E58019260719055E122 /* AdvancedWalletWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0DB5EA5195D9433A4B90793 /* AdvancedWalletWireframe.swift */; }; 2262277544A1D9CB46EF087A /* ParaStkYieldBoostStopProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD0DBD280596DBBC5CE5A8F /* ParaStkYieldBoostStopProtocols.swift */; }; + 2272FB0A01000A46D097634E /* GovernanceUnlockConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E067006C1BC9DFCA5E8DB86 /* GovernanceUnlockConfirmWireframe.swift */; }; 233CB11F486DE1953D977295 /* WalletsListViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7073BBC153295FF46FD06FB3 /* WalletsListViewLayout.swift */; }; 2368E8BFA569B8D007F6244F /* AssetsManageWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFC5052A062548D20D232DA /* AssetsManageWireframe.swift */; }; 237AD34CD1C2778834D7B330 /* AnalyticsValidatorsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F8BBBA9EABA266B288333F /* AnalyticsValidatorsViewFactory.swift */; }; @@ -248,6 +249,7 @@ 61B9688494251703A6373A1B /* StakingAmountWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6216F6F1B91F798F07695FB6 /* StakingAmountWireframe.swift */; }; 61E0DC83C1D60D677274D7CE /* AccountExportPasswordViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11575D8B4F64C2E805372A5 /* AccountExportPasswordViewFactory.swift */; }; 623474C49445578F030291B0 /* ParaStkStakeSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0B2C32E11E2F7F3D4A1D3AB /* ParaStkStakeSetupWireframe.swift */; }; + 62649D3FB6AACB508872C67A /* GovernanceUnlockConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9638E6EDBA41A5772E0033AE /* GovernanceUnlockConfirmInteractor.swift */; }; 63185C6D67EAEB2867069AB9 /* ParitySignerWelcomeProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CBB8745F8C36BB107625E8F /* ParitySignerWelcomeProtocols.swift */; }; 640A79BD1335394818E70366 /* WalletHistoryFilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6884DFC1AA1B995C21C274C /* WalletHistoryFilterViewController.swift */; }; 641D7CF89F37B1890516015E /* ParitySignerTxScanProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F10F130391C4B3652FE8F59 /* ParitySignerTxScanProtocols.swift */; }; @@ -276,6 +278,7 @@ 6D315EFF2B664235D297674E /* AccountImportProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = B29514E516CEAAB159851D95 /* AccountImportProtocols.swift */; }; 6D47EAB127FAB7559A9FA107 /* StakingPayoutConfirmationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BACB7E24BC87F9218DBBC4 /* StakingPayoutConfirmationViewController.swift */; }; 6D5851FB5F830D55EFDB8B7D /* StakingUnbondSetupProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23A74BDB54D503FA2BFBEF35 /* StakingUnbondSetupProtocols.swift */; }; + 6D603098CCF0B65AA726AD38 /* GovernanceUnlockConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B2EBE8C02491A06121705A /* GovernanceUnlockConfirmViewController.swift */; }; 6D61E43A79BDF5EA6CA9E85D /* CrowdloanListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = C191A3875F3255B72E01FA92 /* CrowdloanListWireframe.swift */; }; 6D622CD4A83EEC1F135B66A8 /* ParitySignerAddConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC216C4DBF86A9F3ADB3AECF /* ParitySignerAddConfirmWireframe.swift */; }; 6D6C6FD2F13603BCE83CFC65 /* ExportMnemonicConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC566D6EACB81469B926611 /* ExportMnemonicConfirmInteractor.swift */; }; @@ -312,6 +315,7 @@ 7D2906130F25492872637EFC /* ReferendumDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78536852751EF56F58C5691E /* ReferendumDetailsPresenter.swift */; }; 7D707DDD180999C63FD0C4ED /* AssetListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE26599B4E43DC4CE520528 /* AssetListViewController.swift */; }; 7D7D40581C276D60713822E9 /* ParaStkCollatorFiltersPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39503B664F159E5D07FF6281 /* ParaStkCollatorFiltersPresenter.swift */; }; + 7DB7E81CC2F880E4736DE062 /* GovernanceUnlockConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EE81AE154A736A93FF3812B /* GovernanceUnlockConfirmViewLayout.swift */; }; 7E1A03082260E0D31AD394CA /* StakingRewardDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF891BE39D442C2D06DDF3BB /* StakingRewardDetailsProtocols.swift */; }; 7E2800371BE3B166F3475E90 /* ReferendumVoteSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6CCACED8D5AFA6543845B7 /* ReferendumVoteSetupPresenter.swift */; }; 7E5ACF8DDF17C054E6E1B3D5 /* ParaStkYieldBoostSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C2B3C9875FDA7EE8D168900 /* ParaStkYieldBoostSetupWireframe.swift */; }; @@ -1619,6 +1623,7 @@ 84A6AB64290B021E001B57B2 /* CopyPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A6AB63290B021E001B57B2 /* CopyPresentable.swift */; }; 84A8FD8E265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A8FD8D265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift */; }; 84A90489288EA0E500DFC8E2 /* NoKeysCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A90488288EA0E500DFC8E2 /* NoKeysCommand.swift */; }; + 84A9ECC1291292900094C763 /* GovernanceUnlockConfirmInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A9ECC0291292900094C763 /* GovernanceUnlockConfirmInteractorError.swift */; }; 84AA004326C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AA004226C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift */; }; 84AA004526C6A04A00BCB4DC /* CommonTypesSyncService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AA004426C6A04A00BCB4DC /* CommonTypesSyncService.swift */; }; 84AC0B6A28C0D8CE00FA5B5D /* NoLedgerSupportCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AC0B6928C0D8CE00FA5B5D /* NoLedgerSupportCommand.swift */; }; @@ -2413,6 +2418,7 @@ 9B6CD060F0EB77C162D90D3E /* ChainAddressDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 781FA4C896AF31B4035AFB38 /* ChainAddressDetailsViewFactory.swift */; }; 9BADFCBF3AF5186094DB8D67 /* DAppTxDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB4A14C99D151B41F61F474 /* DAppTxDetailsInteractor.swift */; }; 9D5926790B055C56FB74B282 /* AccountManagementProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B5072E250B7277F605855B3 /* AccountManagementProtocols.swift */; }; + 9DE1757D047A4D1E97913774 /* GovernanceUnlockConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D3FE2CE7F9F2836755DBA63 /* GovernanceUnlockConfirmProtocols.swift */; }; 9DED20EB20A872E682CB402A /* ReferendumFullDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F6DA24E0481A3678F2EF809 /* ReferendumFullDetailsProtocols.swift */; }; 9DFB37659A6B911A4D54623E /* AccountConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E992CCDC1D581F7E9D3F1CA /* AccountConfirmInteractor.swift */; }; 9E15912C35D50C6D738FD04C /* AccountConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5002B8FA2695F470587677D2 /* AccountConfirmProtocols.swift */; }; @@ -2428,6 +2434,7 @@ A2BE8967FC1609D61E4131BE /* ParaStkYieldBoostStopViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2B438707EA6C81C48EAB4CE /* ParaStkYieldBoostStopViewController.swift */; }; A2F7908210A0398EDBBA89BD /* NftDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3CC9CAB00B604CD1AC5B4D8 /* NftDetailsViewFactory.swift */; }; A32E1373E3671D518FFC3BC2 /* YourValidatorListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B90CEC70F101AA25A4C00021 /* YourValidatorListViewController.swift */; }; + A3BDFA01A32B6C7463E6EFFA /* GovernanceUnlockConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513A449CCF5A417B67B7067D /* GovernanceUnlockConfirmPresenter.swift */; }; A5880E3789BC9E30835BDCC7 /* TransferSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8202B83B2DF36439CB6449C6 /* TransferSetupViewFactory.swift */; }; A714CEAF7A86292E8D679056 /* ParaStkStakeSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7955BBDC93BC07D069B8F /* ParaStkStakeSetupViewFactory.swift */; }; A748D64F6048192E16E5BE44 /* ParaStkUnstakeConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CD36AD8C414F8973CDA8A0F /* ParaStkUnstakeConfirmViewLayout.swift */; }; @@ -2639,6 +2646,7 @@ D3F199376DAEBF380C5FFD9D /* DAppAddFavoriteViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A759A20A4A39B3B0E2A735 /* DAppAddFavoriteViewLayout.swift */; }; D565DB5ED3B8B4D9BCFB4C21 /* CustomValidatorListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14E3337CDD7C831AEAA4582F /* CustomValidatorListPresenter.swift */; }; D567BAAF620EDB9F4975C800 /* DAppAuthConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CFAA1D2D04553B10421C69 /* DAppAuthConfirmProtocols.swift */; }; + D5BB3A36DB9ADD25EE43109F /* GovernanceUnlockConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 358E87C8E90981E6D9515745 /* GovernanceUnlockConfirmViewFactory.swift */; }; D600448CB75095E6873E542F /* DAppTxDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D383344BEDAEDC76A6BE2CE /* DAppTxDetailsProtocols.swift */; }; D6511F7C3E55197F82AB552C /* RecommendedValidatorListViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE4AF0849E32E5B9C72E2ABB /* RecommendedValidatorListViewFactory.swift */; }; D6D9D16440AB588F581AF5BA /* ParaStkYourCollatorsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6A6E9A6472158C37D3A62F5 /* ParaStkYourCollatorsPresenter.swift */; }; @@ -2938,6 +2946,7 @@ 00E1485C7B322E477D445C84 /* ChainAddressDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainAddressDetailsProtocols.swift; sourceTree = ""; }; 0100701AA69652CB91ACBD97 /* AssetListInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetListInteractor.swift; sourceTree = ""; }; 01A9D9D13EC9D921A2C8FB6D /* DAppAuthConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthConfirmWireframe.swift; sourceTree = ""; }; + 01B2EBE8C02491A06121705A /* GovernanceUnlockConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmViewController.swift; sourceTree = ""; }; 024B7E67C0603C53981EC394 /* ReferendumVoteSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupInteractor.swift; sourceTree = ""; }; 02ACCC85B2CCF3D9392CA9B4 /* CrowdloanListProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanListProtocols.swift; sourceTree = ""; }; 02D8F02830944DBAF72D8A41 /* MoonbeamTermsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MoonbeamTermsProtocols.swift; sourceTree = ""; }; @@ -2961,6 +2970,7 @@ 0C34D496D0F57E685237B3A7 /* StakingUnbondConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondConfirmInteractor.swift; sourceTree = ""; }; 0C797A5B5863A026E84062AE /* MessageSheetProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MessageSheetProtocols.swift; sourceTree = ""; }; 0CDFFCC54A504417F4ACE7AA /* NftListInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftListInteractor.swift; sourceTree = ""; }; + 0D3FE2CE7F9F2836755DBA63 /* GovernanceUnlockConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmProtocols.swift; sourceTree = ""; }; 0D6E67AD564867E121601F18 /* WalletsListPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletsListPresenter.swift; sourceTree = ""; }; 0D9C85AB0C9D53B522DCF3C5 /* CreateWatchOnlyInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CreateWatchOnlyInteractor.swift; sourceTree = ""; }; 1039AA3654461114FBB86844 /* DAppTxDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsPresenter.swift; sourceTree = ""; }; @@ -2994,6 +3004,7 @@ 1D42F468C639CA69621F0C03 /* LedgerWalletConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerWalletConfirmViewFactory.swift; sourceTree = ""; }; 1DC6917929E4A752B79FE554 /* OperationDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = OperationDetailsWireframe.swift; sourceTree = ""; }; 1DECC58C93DB18E79A03B5A0 /* AssetSelectionProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetSelectionProtocols.swift; sourceTree = ""; }; + 1E067006C1BC9DFCA5E8DB86 /* GovernanceUnlockConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmWireframe.swift; sourceTree = ""; }; 1E5CB64B91B35804B3671456 /* ControllerAccountPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ControllerAccountPresenter.swift; sourceTree = ""; }; 1F3A05E0F46351784030D1AA /* ChainAddressDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainAddressDetailsPresenter.swift; sourceTree = ""; }; 1F3B726402D4DB25059EF156 /* AnalyticsValidatorsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsValidatorsProtocols.swift; sourceTree = ""; }; @@ -3076,6 +3087,7 @@ 3531B386DEF40108C34E7232 /* ReferendumVoteConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmViewLayout.swift; sourceTree = ""; }; 3558BD7D1B8CA1409BE74879 /* AccountManagementInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountManagementInteractor.swift; sourceTree = ""; }; 3574BADE9CF77599048C7010 /* CrowdloanContributionSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupWireframe.swift; sourceTree = ""; }; + 358E87C8E90981E6D9515745 /* GovernanceUnlockConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmViewFactory.swift; sourceTree = ""; }; 35A4A258D911C67F875E386D /* ParaStkCollatorFiltersViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorFiltersViewController.swift; sourceTree = ""; }; 365CAE2753E7D5F9B9DB7D1F /* CustomValidatorListInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CustomValidatorListInteractor.swift; sourceTree = ""; }; 367393F8CA6157A999F69573 /* AssetsSearchViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetsSearchViewLayout.swift; sourceTree = ""; }; @@ -3142,6 +3154,7 @@ 5002B8FA2695F470587677D2 /* AccountConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountConfirmProtocols.swift; sourceTree = ""; }; 502D42F4A480889BA226CAD3 /* StakingMainPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingMainPresenter.swift; sourceTree = ""; }; 50829CD47D3F60E3067418B4 /* ParaStkYieldBoostStartProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStartProtocols.swift; sourceTree = ""; }; + 513A449CCF5A417B67B7067D /* GovernanceUnlockConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmPresenter.swift; sourceTree = ""; }; 5147BFCC44EB3938D50EE8D9 /* DAppPhishingPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppPhishingPresenter.swift; sourceTree = ""; }; 5159EA2661A6CBE123CCF891 /* ReferendumVoteSetupProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupProtocols.swift; sourceTree = ""; }; 518305BB475DE40E94DCBD5D /* DAppPhishingWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppPhishingWireframe.swift; sourceTree = ""; }; @@ -4567,6 +4580,7 @@ 84A6AB63290B021E001B57B2 /* CopyPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyPresentable.swift; sourceTree = ""; }; 84A8FD8D265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmData.swift; sourceTree = ""; }; 84A90488288EA0E500DFC8E2 /* NoKeysCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoKeysCommand.swift; sourceTree = ""; }; + 84A9ECC0291292900094C763 /* GovernanceUnlockConfirmInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmInteractorError.swift; sourceTree = ""; }; 84AA004226C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeSyncServiceTests.swift; sourceTree = ""; }; 84AA004426C6A04A00BCB4DC /* CommonTypesSyncService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonTypesSyncService.swift; sourceTree = ""; }; 84AC0B6928C0D8CE00FA5B5D /* NoLedgerSupportCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoLedgerSupportCommand.swift; sourceTree = ""; }; @@ -5328,6 +5342,7 @@ 8EB322463CF5036819A181E0 /* ParaStkCollatorsSearchViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorsSearchViewController.swift; sourceTree = ""; }; 8EE41915478E28D94B8471A0 /* LedgerNetworkSelectionViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerNetworkSelectionViewController.swift; sourceTree = ""; }; 8EE72F2B6612508D4783A507 /* DAppAuthSettingsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthSettingsProtocols.swift; sourceTree = ""; }; + 8EE81AE154A736A93FF3812B /* GovernanceUnlockConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmViewLayout.swift; sourceTree = ""; }; 8F96182151D003DF6789CB4B /* DAppSearchProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppSearchProtocols.swift; sourceTree = ""; }; 8F9C67FCF466D9EF48ED35D2 /* Pods-novawalletTests.dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-novawalletTests.dev.xcconfig"; path = "Target Support Files/Pods-novawalletTests/Pods-novawalletTests.dev.xcconfig"; sourceTree = ""; }; 8FDF5963FA924F8C815F3BCF /* ParaStkRebondViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRebondViewController.swift; sourceTree = ""; }; @@ -5345,6 +5360,7 @@ 95E4AF529B896F7E58671A74 /* GovernanceUnlockSetupViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupViewFactory.swift; sourceTree = ""; }; 9622C6C3102EF12BEE78D63D /* AssetSelectionViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetSelectionViewFactory.swift; sourceTree = ""; }; 96340EDDE0EAA7F9B6D33E96 /* LedgerWalletConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerWalletConfirmInteractor.swift; sourceTree = ""; }; + 9638E6EDBA41A5772E0033AE /* GovernanceUnlockConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmInteractor.swift; sourceTree = ""; }; 96BE36DA0A2310660A43FF5B /* DAppAddFavoriteInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAddFavoriteInteractor.swift; sourceTree = ""; }; 96D540DFC00C25D8F73CFDC3 /* CustomValidatorListWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CustomValidatorListWireframe.swift; sourceTree = ""; }; 96F09665083031502F9693F8 /* StakingMainWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingMainWireframe.swift; sourceTree = ""; }; @@ -6607,6 +6623,21 @@ path = SelectValidatorsConfirm; sourceTree = ""; }; + 77E4088EF503B8FD414F14EA /* GovernanceUnlockConfirm */ = { + isa = PBXGroup; + children = ( + 84A9ECBF2912925E0094C763 /* Model */, + 0D3FE2CE7F9F2836755DBA63 /* GovernanceUnlockConfirmProtocols.swift */, + 1E067006C1BC9DFCA5E8DB86 /* GovernanceUnlockConfirmWireframe.swift */, + 513A449CCF5A417B67B7067D /* GovernanceUnlockConfirmPresenter.swift */, + 9638E6EDBA41A5772E0033AE /* GovernanceUnlockConfirmInteractor.swift */, + 01B2EBE8C02491A06121705A /* GovernanceUnlockConfirmViewController.swift */, + 8EE81AE154A736A93FF3812B /* GovernanceUnlockConfirmViewLayout.swift */, + 358E87C8E90981E6D9515745 /* GovernanceUnlockConfirmViewFactory.swift */, + ); + path = GovernanceUnlockConfirm; + sourceTree = ""; + }; 788647A9C0A8684C9A8AC310 /* ControllerAccount */ = { isa = PBXGroup; children = ( @@ -8084,6 +8115,7 @@ 845BB8C725E45D0600E5FCDC /* Calls */ = { isa = PBXGroup; children = ( + 84A9ECBE29128D130094C763 /* ConvictionVoting */, 844ADE7C28CB34F600EE29F7 /* AutomationTime */, 84EBFCEC285E82AB0006327E /* Xcm */, 8445CC252836654B003B26CD /* Common */, @@ -8748,6 +8780,7 @@ B320B465EE16F566DDFE5D8C /* ReferendumVoteConfirm */, 847157792910F06000D7D003 /* GovernanceUnlock */, FD4B0C614F7A70D8FB51A1C3 /* GovernanceUnlockSetup */, + 77E4088EF503B8FD414F14EA /* GovernanceUnlockConfirm */, ); path = Governance; sourceTree = ""; @@ -8964,7 +8997,6 @@ 84532D5C28E41D8500EF4ADC /* ConvictionVoting+StoragePath.swift */, 84532D6028E4234700EF4ADC /* ConvictionVotingForKey.swift */, 8448148028E46881007F64FF /* ConvictionVotingLocks.swift */, - 8425D0EF28FE9CF0003B782A /* ConvictionVoting+Call.swift */, 8427495628FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift */, ); path = ConvictionVoting; @@ -10379,6 +10411,22 @@ path = Model; sourceTree = ""; }; + 84A9ECBE29128D130094C763 /* ConvictionVoting */ = { + isa = PBXGroup; + children = ( + 8425D0EF28FE9CF0003B782A /* ConvictionVoting+Call.swift */, + ); + path = ConvictionVoting; + sourceTree = ""; + }; + 84A9ECBF2912925E0094C763 /* Model */ = { + isa = PBXGroup; + children = ( + 84A9ECC0291292900094C763 /* GovernanceUnlockConfirmInteractorError.swift */, + ); + path = Model; + sourceTree = ""; + }; 84ACEBF0261E663700AAE665 /* ViewModel */ = { isa = PBXGroup; children = ( @@ -16595,6 +16643,7 @@ EB9D8D22AA13BF12F845856B /* ReferralCrowdloanProtocols.swift in Sources */, 51FC48FA6FD4D2FB1781424D /* ReferralCrowdloanWireframe.swift in Sources */, 0F3E58FC800ED8722589F89E /* ReferralCrowdloanPresenter.swift in Sources */, + 84A9ECC1291292900094C763 /* GovernanceUnlockConfirmInteractorError.swift in Sources */, 9F4A48B1BE3A1110A0CF9F36 /* ReferralCrowdloanViewController.swift in Sources */, F4B39C6B2732791900BB6E10 /* RadioButton.swift in Sources */, CE2792E78B14CE02394D8CF4 /* ReferralCrowdloanViewLayout.swift in Sources */, @@ -17139,6 +17188,13 @@ 16098DABB1C9C058C1965F1D /* GovernanceUnlockSetupViewController.swift in Sources */, 0E71EA5AE04940824AEA01C7 /* GovernanceUnlockSetupViewLayout.swift in Sources */, E28F3762EAC9A4E5D21342D4 /* GovernanceUnlockSetupViewFactory.swift in Sources */, + 9DE1757D047A4D1E97913774 /* GovernanceUnlockConfirmProtocols.swift in Sources */, + 2272FB0A01000A46D097634E /* GovernanceUnlockConfirmWireframe.swift in Sources */, + A3BDFA01A32B6C7463E6EFFA /* GovernanceUnlockConfirmPresenter.swift in Sources */, + 62649D3FB6AACB508872C67A /* GovernanceUnlockConfirmInteractor.swift in Sources */, + 6D603098CCF0B65AA726AD38 /* GovernanceUnlockConfirmViewController.swift in Sources */, + 7DB7E81CC2F880E4736DE062 /* GovernanceUnlockConfirmViewLayout.swift in Sources */, + D5BB3A36DB9ADD25EE43109F /* GovernanceUnlockConfirmViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Common/Substrate/Calls/ConvictionVoting/ConvictionVoting+Call.swift b/novawallet/Common/Substrate/Calls/ConvictionVoting/ConvictionVoting+Call.swift new file mode 100644 index 0000000000..83ba52451f --- /dev/null +++ b/novawallet/Common/Substrate/Calls/ConvictionVoting/ConvictionVoting+Call.swift @@ -0,0 +1,46 @@ +import Foundation +import SubstrateSdk + +extension ConvictionVoting { + struct VoteCall: Codable { + enum CodingKeys: String, CodingKey { + case referendumIndex = "poll_index" + case vote + } + + @StringCodable var referendumIndex: Referenda.ReferendumIndex + let vote: ConvictionVoting.AccountVote + + var runtimeCall: RuntimeCall { + RuntimeCall(moduleName: "ConvictionVoting", callName: "vote", args: self) + } + } + + struct RemoveVoteCall: Codable { + enum CodingKeys: String, CodingKey { + case track = "class" + case index + } + + @OptionStringCodable var track: Referenda.TrackId? + @StringCodable var index: Referenda.ReferendumIndex + + var runtimeCall: RuntimeCall { + RuntimeCall(moduleName: "ConvictionVoting", callName: "remove_vote", args: self) + } + } + + struct UnlockCall: Codable { + enum CodingKeys: String, CodingKey { + case track = "class" + case target + } + + @StringCodable var track: Referenda.TrackId + let target: MultiAddress + + var runtimeCall: RuntimeCall { + RuntimeCall(moduleName: "ConvictionVoting", callName: "unlock", args: self) + } + } +} diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+Call.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+Call.swift deleted file mode 100644 index 0b2dfa47ab..0000000000 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting+Call.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation -import SubstrateSdk - -extension ConvictionVoting { - struct VoteCall: Codable { - enum CodingKeys: String, CodingKey { - case referendumIndex = "poll_index" - case vote - } - - @StringCodable var referendumIndex: Referenda.ReferendumIndex - let vote: ConvictionVoting.AccountVote - - var runtimeCall: RuntimeCall { - RuntimeCall(moduleName: "ConvictionVoting", callName: "vote", args: self) - } - } -} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift new file mode 100644 index 0000000000..9c553bd9c0 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift @@ -0,0 +1,145 @@ +import UIKit +import SubstrateSdk +import RobinHood +import BigInt + +final class GovernanceUnlockConfirmInteractor: GovernanceUnlockInteractor, AnyProviderAutoCleaning { + var presenter: GovernanceUnlockConfirmInteractorOutputProtocol? { + get { + basePresenter as? GovernanceUnlockConfirmInteractorOutputProtocol + } + + set { + basePresenter = newValue + } + } + + let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol + let extrinsicFactory: GovernanceExtrinsicFactoryProtocol + let extrinsicService: ExtrinsicServiceProtocol + let signer: SigningWrapperProtocol + + private var locksSubscription: StreamableProvider? + + init( + chain: ChainModel, + selectedAccount: MetaChainAccountResponse, + subscriptionFactory: GovernanceSubscriptionFactoryProtocol, + lockStateFactory: GovernanceLockStateFactoryProtocol, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, + extrinsicFactory: GovernanceExtrinsicFactoryProtocol, + extrinsicService: ExtrinsicServiceProtocol, + signer: SigningWrapperProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, + blockTimeService: BlockTimeEstimationServiceProtocol, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + operationQueue: OperationQueue + ) { + self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory + self.extrinsicFactory = extrinsicFactory + self.extrinsicService = extrinsicService + self.signer = signer + + super.init( + chain: chain, + selectedAccount: selectedAccount, + subscriptionFactory: subscriptionFactory, + lockStateFactory: lockStateFactory, + priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, + generalLocalSubscriptionFactory: generalLocalSubscriptionFactory, + blockTimeService: blockTimeService, + connection: connection, + runtimeProvider: runtimeProvider, + operationQueue: operationQueue + ) + } + + private func clearAndSubscribeLocks() { + clear(streamableProvider: &locksSubscription) + + guard let assetId = chain.utilityAsset()?.assetId else { + return + } + + locksSubscription = subscribeToLocksProvider( + for: selectedAccount.chainAccount.accountId, + chainId: chain.chainId, + assetId: assetId + ) + } + + private func createExtrinsicBuilderClosure(for actions: Set) -> ExtrinsicBuilderClosure { + { [weak self] builder in + guard let strongSelf = self else { + return builder + } + + return try strongSelf.extrinsicFactory.unlock( + with: actions, + accountId: strongSelf.selectedAccount.chainAccount.accountId, + builder: builder + ) + } + } + + override func setup() { + super.setup() + + clearAndSubscribeLocks() + } + + override func remakeSubscriptions() { + super.remakeSubscriptions() + + clearAndSubscribeLocks() + } +} + +extension GovernanceUnlockConfirmInteractor: GovernanceUnlockConfirmInteractorInputProtocol { + func estimateFee(for actions: Set) { + let closure = createExtrinsicBuilderClosure(for: actions) + + extrinsicService.estimateFee(closure, runningIn: .main) { [weak self] result in + switch result { + case let .success(feeInfo): + if let fee = BigUInt(feeInfo.fee) { + self?.presenter?.didReceiveFee(fee) + } + case let .failure(error): + self?.presenter?.didReceiveError(.feeFetchFailed(error)) + } + } + } + + func unlock(using actions: Set) { + let closure = createExtrinsicBuilderClosure(for: actions) + + extrinsicService.submit(closure, signer: signer, runningIn: .main) { [weak self] result in + switch result { + case let .success(hashString): + self?.presenter?.didReceiveUnlockHash(hashString) + case let .failure(error): + self?.presenter?.didReceiveError(.unlockFailed(error)) + } + } + } +} + +extension GovernanceUnlockConfirmInteractor: WalletLocalStorageSubscriber, WalletLocalSubscriptionHandler { + func handleAccountLocks( + result: Result<[DataProviderChange], Error>, + accountId _: AccountId, + chainId _: ChainModel.Id, + assetId _: AssetModel.Id + ) { + switch result { + case let .success(changes): + let locks = changes.mergeToDict([:]).values + presenter?.didReceiveLocks(Array(locks)) + case let .failure(error): + presenter?.didReceiveError(.locksSubscriptionFailed(error)) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift new file mode 100644 index 0000000000..be6231a96b --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift @@ -0,0 +1,21 @@ +import Foundation + +final class GovernanceUnlockConfirmPresenter { + weak var view: GovernanceUnlockConfirmViewProtocol? + let wireframe: GovernanceUnlockConfirmWireframeProtocol + let interactor: GovernanceUnlockConfirmInteractorInputProtocol + + init( + interactor: GovernanceUnlockConfirmInteractorInputProtocol, + wireframe: GovernanceUnlockConfirmWireframeProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + } +} + +extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmPresenterProtocol { + func setup() {} +} + +extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmInteractorOutputProtocol {} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift new file mode 100644 index 0000000000..989f2ecb5c --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift @@ -0,0 +1,23 @@ +import BigInt + +protocol GovernanceUnlockConfirmViewProtocol: ControllerBackedProtocol {} + +protocol GovernanceUnlockConfirmPresenterProtocol: AnyObject { + func setup() +} + +protocol GovernanceUnlockConfirmInteractorInputProtocol: GovernanceUnlockInteractorInputProtocol { + func estimateFee(for actions: Set) + func unlock(using actions: Set) +} + +protocol GovernanceUnlockConfirmInteractorOutputProtocol: GovernanceUnlockInteractorOutputProtocol { + func didReceiveLocks(_ locks: AssetLocks) + func didReceiveUnlockHash(_ hash: String) + func didReceiveFee(_ fee: BigUInt) + func didReceiveError(_ error: GovernanceUnlockConfirmInteractorError) +} + +protocol GovernanceUnlockConfirmWireframeProtocol: AlertPresentable, CommonRetryable, + MessageSheetPresentable, AddressOptionsPresentable, + ExtrinsicSubmissionPresenting, GovernanceErrorPresentable {} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift new file mode 100644 index 0000000000..fc1ee84368 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift @@ -0,0 +1,29 @@ +import UIKit + +final class GovernanceUnlockConfirmViewController: UIViewController { + typealias RootViewType = GovernanceUnlockConfirmViewLayout + + let presenter: GovernanceUnlockConfirmPresenterProtocol + + init(presenter: GovernanceUnlockConfirmPresenterProtocol) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = GovernanceUnlockConfirmViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + presenter.setup() + } +} + +extension GovernanceUnlockConfirmViewController: GovernanceUnlockConfirmViewProtocol {} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift new file mode 100644 index 0000000000..bd12e6b612 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift @@ -0,0 +1,17 @@ +import Foundation + +struct GovernanceUnlockConfirmViewFactory { + static func createView(for state: GovernanceSharedState) -> GovernanceUnlockConfirmViewProtocol? { + let interactor = GovernanceUnlockConfirmInteractor() + let wireframe = GovernanceUnlockConfirmWireframe() + + let presenter = GovernanceUnlockConfirmPresenter(interactor: interactor, wireframe: wireframe) + + let view = GovernanceUnlockConfirmViewController(presenter: presenter) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift new file mode 100644 index 0000000000..779ac81665 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift @@ -0,0 +1,13 @@ +import UIKit + +final class GovernanceUnlockConfirmViewLayout: UIView { + + override init(frame: CGRect) { + super.init(frame: frame) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmWireframe.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmWireframe.swift new file mode 100644 index 0000000000..88c57355ed --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class GovernanceUnlockConfirmWireframe: GovernanceUnlockConfirmWireframeProtocol {} \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInteractorError.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInteractorError.swift new file mode 100644 index 0000000000..4ce7c9237e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInteractorError.swift @@ -0,0 +1,7 @@ +import Foundation + +enum GovernanceUnlockConfirmInteractorError { + case locksSubscriptionFailed(_ internalError: Error) + case feeFetchFailed(_ internalError: Error) + case unlockFailed(_ internalError: Error) +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift index f52fa96745..abf8b94ed1 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift @@ -21,4 +21,45 @@ final class Gov2ExtrinsicFactory: GovernanceExtrinsicFactoryProtocol { return try builder.adding(call: voteCall.runtimeCall) } + + func unlock( + with actions: Set, + accountId: AccountId, + builder: ExtrinsicBuilderProtocol + ) throws -> ExtrinsicBuilderProtocol { + let removeVoteCalls: [RuntimeCall] = actions.compactMap { action in + switch action { + case .unvote(let track, let index): + return ConvictionVoting.RemoveVoteCall( + track: Referenda.TrackId(track), + index: Referenda.ReferendumIndex(index) + ).runtimeCall + case .unlock: + return nil + } + } + + let unlockCalls: [RuntimeCall] = actions.compactMap { action in + switch action { + case let .unlock(track): + return ConvictionVoting.UnlockCall( + track: Referenda.TrackId(track), + target: .accoundId(accountId) + ).runtimeCall + case .unvote: + return nil + } + } + + let newBuilder = try appendCalls(removeVoteCalls, builder: builder) + + return try appendCalls(unlockCalls, builder: newBuilder) + } + + private func appendCalls( + _ calls: [C], + builder: ExtrinsicBuilderProtocol + ) throws -> ExtrinsicBuilderProtocol { + try calls.reduce(builder) { try $0.adding(call: $1) } + } } diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceExtrinsicFactoryProtocol.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceExtrinsicFactoryProtocol.swift index c7e8e292c5..7e3c993e08 100644 --- a/novawallet/Modules/Vote/Governance/Operation/GovernanceExtrinsicFactoryProtocol.swift +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceExtrinsicFactoryProtocol.swift @@ -7,4 +7,10 @@ protocol GovernanceExtrinsicFactoryProtocol { referendum: ReferendumIdLocal, builder: ExtrinsicBuilderProtocol ) throws -> ExtrinsicBuilderProtocol + + func unlock( + with actions: Set, + accountId: AccountId, + builder: ExtrinsicBuilderProtocol + ) throws -> ExtrinsicBuilderProtocol } From da58509c8ea9653afb17fd6e7c4f11f1e6b076ce Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 3 Nov 2022 00:26:30 +0500 Subject: [PATCH 147/229] add ui and presenter --- novawallet.xcodeproj/project.pbxproj | 12 + novawallet/Common/View/HintListView.swift | 26 +- .../GovernanceUnlockConfirmInteractor.swift | 24 ++ .../GovernanceUnlockConfirmPresenter.swift | 287 +++++++++++++++++- .../GovernanceUnlockConfirmProtocols.swift | 15 +- ...overnanceUnlockConfirmViewController.swift | 89 +++++- .../GovernanceUnlockConfirmViewFactory.swift | 6 +- .../GovernanceUnlockConfirmViewLayout.swift | 81 ++++- ...vernanceUnlockConfirmInteractorError.swift | 1 + .../GovernanceRemainedLockViewModel.swift | 6 + .../Model/GovernanceUnlockSchedule.swift | 2 +- .../ReferendumVoteConfirmViewLayout.swift | 2 + ...ReferendumLockChangeViewModelFactory.swift | 83 ++++- 13 files changed, 602 insertions(+), 32 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/ViewModel/GovernanceRemainedLockViewModel.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 5e8ea45880..f36f1563f7 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1624,6 +1624,7 @@ 84A8FD8E265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A8FD8D265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift */; }; 84A90489288EA0E500DFC8E2 /* NoKeysCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A90488288EA0E500DFC8E2 /* NoKeysCommand.swift */; }; 84A9ECC1291292900094C763 /* GovernanceUnlockConfirmInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A9ECC0291292900094C763 /* GovernanceUnlockConfirmInteractorError.swift */; }; + 84A9ECC429129FF10094C763 /* GovernanceRemainedLockViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A9ECC329129FF10094C763 /* GovernanceRemainedLockViewModel.swift */; }; 84AA004326C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AA004226C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift */; }; 84AA004526C6A04A00BCB4DC /* CommonTypesSyncService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AA004426C6A04A00BCB4DC /* CommonTypesSyncService.swift */; }; 84AC0B6A28C0D8CE00FA5B5D /* NoLedgerSupportCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AC0B6928C0D8CE00FA5B5D /* NoLedgerSupportCommand.swift */; }; @@ -4581,6 +4582,7 @@ 84A8FD8D265FDA76002ADB58 /* CrowdloanContributionConfirmData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmData.swift; sourceTree = ""; }; 84A90488288EA0E500DFC8E2 /* NoKeysCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoKeysCommand.swift; sourceTree = ""; }; 84A9ECC0291292900094C763 /* GovernanceUnlockConfirmInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmInteractorError.swift; sourceTree = ""; }; + 84A9ECC329129FF10094C763 /* GovernanceRemainedLockViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceRemainedLockViewModel.swift; sourceTree = ""; }; 84AA004226C5DFD800BCB4DC /* RuntimeSyncServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeSyncServiceTests.swift; sourceTree = ""; }; 84AA004426C6A04A00BCB4DC /* CommonTypesSyncService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonTypesSyncService.swift; sourceTree = ""; }; 84AC0B6928C0D8CE00FA5B5D /* NoLedgerSupportCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoLedgerSupportCommand.swift; sourceTree = ""; }; @@ -6626,6 +6628,7 @@ 77E4088EF503B8FD414F14EA /* GovernanceUnlockConfirm */ = { isa = PBXGroup; children = ( + 84A9ECC229129F360094C763 /* ViewModel */, 84A9ECBF2912925E0094C763 /* Model */, 0D3FE2CE7F9F2836755DBA63 /* GovernanceUnlockConfirmProtocols.swift */, 1E067006C1BC9DFCA5E8DB86 /* GovernanceUnlockConfirmWireframe.swift */, @@ -10427,6 +10430,14 @@ path = Model; sourceTree = ""; }; + 84A9ECC229129F360094C763 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 84A9ECC329129FF10094C763 /* GovernanceRemainedLockViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; 84ACEBF0261E663700AAE665 /* ViewModel */ = { isa = PBXGroup; children = ( @@ -14514,6 +14525,7 @@ buildActionMask = 2147483647; files = ( 842A735B27DB1EDE006EE1EA /* OperationDetailsCommand.swift in Sources */, + 84A9ECC429129FF10094C763 /* GovernanceRemainedLockViewModel.swift in Sources */, F4C2009C2727ED1C00B0F3D0 /* SystemRemarkCall.swift in Sources */, AEF505102616769F0098574D /* InitiatedBonding.swift in Sources */, 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */, diff --git a/novawallet/Common/View/HintListView.swift b/novawallet/Common/View/HintListView.swift index 21b567ddf4..1e47c31a95 100644 --- a/novawallet/Common/View/HintListView.swift +++ b/novawallet/Common/View/HintListView.swift @@ -25,20 +25,24 @@ class HintListView: UIView { fatalError("init(coder:) has not been implemented") } - func bind(texts: [String]) { - if texts.count < hints.count { - let hintsToRemove = hints.suffix(hints.count - texts.count) - hints = Array(hints.prefix(texts.count)) + private func updateHints(for newCount: Int) { + if newCount < hints.count { + let hintsToRemove = hints.suffix(hints.count - newCount) + hints = Array(hints.prefix(newCount)) hintsToRemove.forEach { $0.removeFromSuperview() } - } else if texts.count > hints.count { - let addHintsCount = texts.count - hints.count + } else if newCount > hints.count { + let addHintsCount = newCount - hints.count let newHints = (0 ..< addHintsCount).map { _ in IconDetailsView.hint() } newHints.forEach { stackView.addArrangedSubview($0) } hints += newHints } + } + + func bind(texts: [String]) { + updateHints(for: texts.count) for (text, hint) in zip(texts, hints) { hint.detailsLabel.text = text @@ -47,6 +51,16 @@ class HintListView: UIView { setNeedsLayout() } + func bind(attributedTexts: [NSAttributedString]) { + updateHints(for: attributedTexts.count) + + for (text, hint) in zip(attributedTexts, hints) { + hint.detailsLabel.attributedText = text + } + + setNeedsLayout() + } + private func setupLayout() { addSubview(stackView) stackView.snp.makeConstraints { make in diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift index 9c553bd9c0..8028d2059e 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift @@ -20,6 +20,7 @@ final class GovernanceUnlockConfirmInteractor: GovernanceUnlockInteractor, AnyPr let signer: SigningWrapperProtocol private var locksSubscription: StreamableProvider? + private var assetBalanceProvider: StreamableProvider? init( chain: ChainModel, @@ -70,6 +71,20 @@ final class GovernanceUnlockConfirmInteractor: GovernanceUnlockInteractor, AnyPr ) } + private func clearAndSubscribeBalance() { + clear(streamableProvider: &assetBalanceProvider) + + guard let assetId = chain.utilityAsset()?.assetId else { + return + } + + assetBalanceProvider = subscribeToAssetBalanceProvider( + for: selectedAccount.chainAccount.accountId, + chainId: chain.chainId, + assetId: assetId + ) + } + private func createExtrinsicBuilderClosure(for actions: Set) -> ExtrinsicBuilderClosure { { [weak self] builder in guard let strongSelf = self else { @@ -142,4 +157,13 @@ extension GovernanceUnlockConfirmInteractor: WalletLocalStorageSubscriber, Walle presenter?.didReceiveError(.locksSubscriptionFailed(error)) } } + + func handleAssetBalance( + result: Result, + accountId: AccountId, + chainId: ChainModel.Id, + assetId: AssetModel.Id + ) { + + } } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift index be6231a96b..19649254c0 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift @@ -1,21 +1,302 @@ import Foundation +import BigInt +import SoraFoundation +import BigInt final class GovernanceUnlockConfirmPresenter { weak var view: GovernanceUnlockConfirmViewProtocol? let wireframe: GovernanceUnlockConfirmWireframeProtocol let interactor: GovernanceUnlockConfirmInteractorInputProtocol + let chain: ChainModel + let selectedAccount: MetaChainAccountResponse + let balanceViewModelFactory: BalanceViewModelFactoryProtocol + let lockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol + let dataValidatingFactory: GovernanceValidatorFactoryProtocol + let logger: LoggerProtocol + + private var votingResult: CallbackStorageSubscriptionResult? + private var unlockSchedule: GovernanceUnlockSchedule + private var locks: AssetLocks? + private var assetBalance: AssetBalance? + private var blockNumber: BlockNumber + private var price: PriceData? + private var fee: BigUInt? + + private lazy var walletDisplayViewModelFactory = WalletAccountViewModelFactory() + private lazy var addressDisplayViewModelFactory = DisplayAddressViewModelFactory() + init( interactor: GovernanceUnlockConfirmInteractorInputProtocol, - wireframe: GovernanceUnlockConfirmWireframeProtocol + wireframe: GovernanceUnlockConfirmWireframeProtocol, + chain: ChainModel, + selectedAccount: MetaChainAccountResponse, + schedule: GovernanceUnlockSchedule, + blockNumber: BlockNumber, + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + lockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol, + dataValidatingFactory: GovernanceValidatorFactoryProtocol, + localizationManager: LocalizationManagerProtocol, + logger: LoggerProtocol ) { self.interactor = interactor self.wireframe = wireframe + self.chain = chain + self.selectedAccount = selectedAccount + self.unlockSchedule = schedule + self.blockNumber = blockNumber + self.balanceViewModelFactory = balanceViewModelFactory + self.lockChangeViewModelFactory = lockChangeViewModelFactory + self.dataValidatingFactory = dataValidatingFactory + self.logger = logger + self.localizationManager = localizationManager + } + + private func provideAmountViewModel() { + let amount = unlockSchedule.availableUnlock(at: blockNumber).amount + + guard + let precision = chain.utilityAsset()?.displayInfo.assetPrecision, + let decimalAmount = Decimal.fromSubstrateAmount(amount, precision: precision) else { + return + } + + let viewModel = balanceViewModelFactory.balanceFromPrice( + decimalAmount, + priceData: price + ).value(for: selectedLocale) + + view?.didReceiveAmount(viewModel: viewModel) + } + + private func provideWalletViewModel() { + guard + let viewModel = try? walletDisplayViewModelFactory.createDisplayViewModel( + from: selectedAccount + ) else { + return + } + + view?.didReceiveWallet(viewModel: viewModel.cellViewModel) + } + + private func provideAccountViewModel() { + guard let address = selectedAccount.chainAccount.toAddress() else { + return + } + + let viewModel = addressDisplayViewModelFactory.createViewModel(from: address) + view?.didReceiveAccount(viewModel: viewModel) + } + + private func provideFeeViewModel() { + if let fee = fee { + guard let precision = chain.utilityAsset()?.displayInfo.assetPrecision else { + return + } + + let feeDecimal = Decimal.fromSubstrateAmount( + fee, + precision: precision + ) ?? 0.0 + + let viewModel = balanceViewModelFactory.balanceFromPrice(feeDecimal, priceData: price) + .value(for: selectedLocale) + + view?.didReceiveFee(viewModel: viewModel) + } else { + view?.didReceiveFee(viewModel: nil) + } + } + + private func provideTransferableViewModel() { + + } + + private func provideChangesViewModels() { + guard let tracksVoting = votingResult?.value else { + return + } + + let totalLocked = tracksVoting.totalLocked() + let unlocking = unlockSchedule.availableUnlock(at: blockNumber).amount + let remainedLocked = totalLocked > unlocking ? totalLocked - unlocking : 0 + + if + let govViewModel = lockChangeViewModelFactory.createAmountViewModel( + initLocked: totalLocked, + resultLocked: remainedLocked, + locale: selectedLocale + ) { + view?.didReceiveLockedAmount(viewModel: govViewModel) + } + + if + let assetBalance = assetBalance, + let locks = locks, + let transferableViewModel = lockChangeViewModelFactory.createTransferableAmountViewModel( + resultLocked: remainedLocked, + balance: assetBalance, + locks: locks, + locale: selectedLocale + ) { + view?.didReceiveTransferableAmount(viewModel: transferableViewModel) + } + } + + private func updateView() { + provideAmountViewModel() + provideWalletViewModel() + provideAccountViewModel() + provideFeeViewModel() + provideChangesViewModels() + } + + private func refreshFee() { + fee = nil + + provideFeeViewModel() + + let actions = unlockSchedule.availableUnlock(at: blockNumber).actions + + guard !actions.isEmpty else { + fee = 0 + + provideFeeViewModel() + + return + } + + interactor.estimateFee(for: actions) + } + + private func refreshUnlockSchedule() { + guard let tracksVoting = votingResult?.value else { + return + } + + interactor.refreshUnlockSchedule(for: tracksVoting, blockHash: nil) } } extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmPresenterProtocol { - func setup() {} + func setup() { + updateView() + + interactor.setup() + + refreshFee() + } +} + +extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmInteractorOutputProtocol { + func didReceiveBalance(_ assetBalance: AssetBalance?) { + self.assetBalance = assetBalance + + provideChangesViewModels() + } + + func didReceiveLocks(_ locks: AssetLocks) { + self.locks = locks + + provideChangesViewModels() + } + + func didReceiveUnlockHash(_ hash: String) { + view?.didStopLoading() + + wireframe.presentExtrinsicSubmission(from: view, completionAction: .dismiss, locale: selectedLocale) + } + + func didReceiveFee(_ fee: BigUInt) { + self.fee = fee + + provideFeeViewModel() + } + + func didReceiveError(_ error: GovernanceUnlockConfirmInteractorError) { + logger.error("Did receive error: \(error)") + + switch error { + case .locksSubscriptionFailed, .balanceSubscriptionFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + case .feeFetchFailed: + wireframe.presentFeeStatus(on: view, locale: selectedLocale) { [weak self] in + self?.refreshFee() + } + case let .unlockFailed(internalError): + view?.didStopLoading() + + if internalError.isWatchOnlySigning { + wireframe.presentDismissingNoSigningView(from: view) + } else { + _ = wireframe.present(error: internalError, from: view, locale: selectedLocale) + } + } + } + + func didReceiveVoting(_ result: CallbackStorageSubscriptionResult) { + self.votingResult = result + + if let tracksVoting = result.value { + interactor.refreshUnlockSchedule(for: tracksVoting, blockHash: result.blockHash) + } + + provideChangesViewModels() + } + + func didReceiveUnlockSchedule(_ schedule: GovernanceUnlockSchedule) { + if schedule != unlockSchedule { + self.unlockSchedule = schedule + + provideChangesViewModels() + provideAmountViewModel() + refreshFee() + } + } + + func didReceiveBlockNumber(_ block: BlockNumber) { + self.blockNumber = block + + provideFeeViewModel() + + provideChangesViewModels() + provideAmountViewModel() + refreshUnlockSchedule() + } + + func didReceiveBlockTime(_ time: BlockTime) {} + + func didReceivePrice(_ price: PriceData?) { + self.price = price + + provideAmountViewModel() + } + + func didReceiveBaseError(_ error: GovernanceUnlockInteractorError) { + logger.error("Did receive base error: \(error)") + + switch error { + case .votingSubscriptionFailed, .priceSubscriptionFailed, .blockNumberSubscriptionFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.remakeSubscriptions() + } + case .unlockScheduleFetchFailed: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.refreshUnlockSchedule() + } + case .blockTimeFetchFailed: + break + } + } } -extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmInteractorOutputProtocol {} \ No newline at end of file +extension GovernanceUnlockConfirmPresenter: Localizable { + func applyLocalization() { + if let view = view, view.isSetup { + updateView() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift index 989f2ecb5c..a9f3469b47 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift @@ -1,6 +1,14 @@ import BigInt -protocol GovernanceUnlockConfirmViewProtocol: ControllerBackedProtocol {} +protocol GovernanceUnlockConfirmViewProtocol: ControllerBackedProtocol, LoadableViewProtocol { + func didReceiveAmount(viewModel: BalanceViewModelProtocol) + func didReceiveWallet(viewModel: StackCellViewModel) + func didReceiveAccount(viewModel: DisplayAddressViewModel) + func didReceiveFee(viewModel: BalanceViewModelProtocol?) + func didReceiveTransferableAmount(viewModel: ReferendumLockTransitionViewModel) + func didReceiveLockedAmount(viewModel: ReferendumLockTransitionViewModel) + func didReceiveRemainedLock(viewModel: GovernanceRemainedLockViewModel?) +} protocol GovernanceUnlockConfirmPresenterProtocol: AnyObject { func setup() @@ -12,12 +20,13 @@ protocol GovernanceUnlockConfirmInteractorInputProtocol: GovernanceUnlockInterac } protocol GovernanceUnlockConfirmInteractorOutputProtocol: GovernanceUnlockInteractorOutputProtocol { + func didReceiveBalance(_ assetBalance: AssetBalance?) func didReceiveLocks(_ locks: AssetLocks) func didReceiveUnlockHash(_ hash: String) func didReceiveFee(_ fee: BigUInt) func didReceiveError(_ error: GovernanceUnlockConfirmInteractorError) } -protocol GovernanceUnlockConfirmWireframeProtocol: AlertPresentable, CommonRetryable, - MessageSheetPresentable, AddressOptionsPresentable, +protocol GovernanceUnlockConfirmWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, + FeeRetryable, MessageSheetPresentable, AddressOptionsPresentable, ExtrinsicSubmissionPresenting, GovernanceErrorPresentable {} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift index fc1ee84368..1609c5ceb5 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift @@ -1,13 +1,19 @@ import UIKit +import SoraFoundation -final class GovernanceUnlockConfirmViewController: UIViewController { +final class GovernanceUnlockConfirmViewController: UIViewController, ViewHolder { typealias RootViewType = GovernanceUnlockConfirmViewLayout let presenter: GovernanceUnlockConfirmPresenterProtocol - init(presenter: GovernanceUnlockConfirmPresenterProtocol) { + init( + presenter: GovernanceUnlockConfirmPresenterProtocol, + localizationManager: LocalizationManagerProtocol + ) { self.presenter = presenter super.init(nibName: nil, bundle: nil) + + self.localizationManager = localizationManager } @available(*, unavailable) @@ -22,8 +28,85 @@ final class GovernanceUnlockConfirmViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + setupLocalization() + presenter.setup() } + + private func setupLocalization() { + let languages = selectedLocale.rLanguages + + title = R.string.localizable.commonUnlock(preferredLanguages: languages) + + rootView.walletCell.titleLabel.text = R.string.localizable.commonWallet( + preferredLanguages: languages + ) + + rootView.accountCell.titleLabel.text = R.string.localizable.commonSender( + preferredLanguages: languages + ) + + rootView.feeCell.rowContentView.locale = selectedLocale + + rootView.transferableTitleLabel.text = R.string.localizable.walletBalanceAvailable( + preferredLanguages: languages + ) + + rootView.lockAmountTitleLabel.text = R.string.localizable.commonGovLock( + preferredLanguages: languages + ) + + rootView.actionLoadableView.actionButton.imageWithTitleView?.title = R.string.localizable + .commonConfirm(preferredLanguages: selectedLocale.rLanguages) + } } -extension GovernanceUnlockConfirmViewController: GovernanceUnlockConfirmViewProtocol {} \ No newline at end of file +extension GovernanceUnlockConfirmViewController: GovernanceUnlockConfirmViewProtocol { + func didReceiveAmount(viewModel: BalanceViewModelProtocol) { + rootView.amountView.bind(viewModel: viewModel) + } + + func didReceiveWallet(viewModel: StackCellViewModel) { + rootView.walletCell.bind(viewModel: viewModel) + } + + func didReceiveAccount(viewModel: DisplayAddressViewModel) { + rootView.accountCell.bind(viewModel: viewModel.cellViewModel) + } + + func didReceiveFee(viewModel: BalanceViewModelProtocol?) { + rootView.feeCell.rowContentView.bind(viewModel: viewModel) + } + + func didReceiveTransferableAmount(viewModel: ReferendumLockTransitionViewModel) { + rootView.transferableCell.bind(viewModel: viewModel) + } + + func didReceiveLockedAmount(viewModel: ReferendumLockTransitionViewModel) { + rootView.lockedAmountCell.bind(viewModel: viewModel) + } + + func didReceiveRemainedLock(viewModel: GovernanceRemainedLockViewModel?) { + if let viewModel = viewModel { + + } else { + rootView.hintsView.bind(texts: [""]) + } + } + + func didStartLoading() { + rootView.actionLoadableView.startLoading() + } + + func didStopLoading() { + rootView.actionLoadableView.stopLoading() + } +} + +extension GovernanceUnlockConfirmViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + setupLocalization() + } + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift index bd12e6b612..62d81fdaa8 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift @@ -1,7 +1,11 @@ import Foundation struct GovernanceUnlockConfirmViewFactory { - static func createView(for state: GovernanceSharedState) -> GovernanceUnlockConfirmViewProtocol? { + static func createView( + for state: GovernanceSharedState, + schedule: GovernanceUnlockSchedule, + blockNumber: BlockNumber + ) -> GovernanceUnlockConfirmViewProtocol? { let interactor = GovernanceUnlockConfirmInteractor() let wireframe = GovernanceUnlockConfirmWireframe() diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift index 779ac81665..de1327056c 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift @@ -1,13 +1,92 @@ import UIKit final class GovernanceUnlockConfirmViewLayout: UIView { + let containerView: ScrollableContainerView = { + let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) + view.stackView.layoutMargins = UIEdgeInsets(top: 0.0, left: 16.0, bottom: 0.0, right: 16.0) + view.stackView.isLayoutMarginsRelativeArrangement = true + view.stackView.alignment = .fill + return view + }() + + let amountView = MultilineBalanceView() + + let senderTableView = StackTableView() + + let walletCell = StackTableCell() + + let accountCell: StackInfoTableCell = { + let cell = StackInfoTableCell() + cell.detailsLabel.lineBreakMode = .byTruncatingMiddle + return cell + }() + + let feeCell = StackNetworkFeeCell() + + let changesTableView = StackTableView() + + var transferableTitleLabel: UILabel { + transferableCell.rowContentView.titleView.detailsLabel + } + + var transferableCell: StackTitleValueDiffCell = .create { cell in + cell.rowContentView.titleView.imageView.image = R.image.iconGovTransferable() + } + + var lockAmountTitleLabel: UILabel { + lockedAmountCell.rowContentView.titleView.detailsLabel + } + + let lockedAmountCell: StackTitleValueDiffCell = .create { cell in + cell.rowContentView.titleView.imageView.image = R.image.iconGovAmountLock() + } + + let hintsView = HintListView() + + let actionLoadableView = LoadableActionView() override init(frame: CGRect) { super.init(frame: frame) + + backgroundColor = R.color.colorBlack() + + setupLayout() } @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } -} \ No newline at end of file + + private func setupLayout() { + addSubview(actionLoadableView) + actionLoadableView.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(UIConstants.horizontalInset) + make.bottom.equalTo(safeAreaLayoutGuide).inset(UIConstants.actionBottomInset) + make.height.equalTo(UIConstants.actionHeight) + } + + addSubview(containerView) + containerView.snp.makeConstraints { make in + make.top.leading.trailing.equalToSuperview() + make.bottom.equalTo(actionLoadableView.snp.top).offset(-8.0) + } + + containerView.stackView.addArrangedSubview(amountView) + containerView.stackView.setCustomSpacing(20.0, after: amountView) + + containerView.stackView.addArrangedSubview(senderTableView) + containerView.stackView.setCustomSpacing(12.0, after: senderTableView) + + senderTableView.addArrangedSubview(walletCell) + senderTableView.addArrangedSubview(accountCell) + senderTableView.addArrangedSubview(feeCell) + + containerView.stackView.addArrangedSubview(changesTableView) + + changesTableView.addArrangedSubview(transferableCell) + changesTableView.addArrangedSubview(lockedAmountCell) + + containerView.stackView.addArrangedSubview(hintsView) + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInteractorError.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInteractorError.swift index 4ce7c9237e..bb551d7848 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInteractorError.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInteractorError.swift @@ -2,6 +2,7 @@ import Foundation enum GovernanceUnlockConfirmInteractorError { case locksSubscriptionFailed(_ internalError: Error) + case balanceSubscriptionFailed(_ internalError: Error) case feeFetchFailed(_ internalError: Error) case unlockFailed(_ internalError: Error) } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/ViewModel/GovernanceRemainedLockViewModel.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/ViewModel/GovernanceRemainedLockViewModel.swift new file mode 100644 index 0000000000..cadbd8b0c5 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/ViewModel/GovernanceRemainedLockViewModel.swift @@ -0,0 +1,6 @@ +import Foundation + +struct GovernanceRemainedLockViewModel { + let amount: String + let modules: [String] +} diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift index 027cf6c7cd..b2afda7a72 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceUnlockSchedule.swift @@ -1,7 +1,7 @@ import Foundation import BigInt -struct GovernanceUnlockSchedule { +struct GovernanceUnlockSchedule: Equatable { enum Action: Equatable, Hashable { case unvote(track: TrackIdLocal, index: ReferendumIdLocal) case unlock(track: TrackIdLocal) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift index ec8aac878c..c168ff462e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift @@ -100,5 +100,7 @@ final class ReferendumVoteConfirmViewLayout: UIView { changesTableView.addArrangedSubview(transferableCell) changesTableView.addArrangedSubview(lockedAmountCell) changesTableView.addArrangedSubview(lockedPeriodCell) + + containerView.stackView.addArrangedSubview(hintsView) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift index 680274893d..83051f7f48 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift @@ -1,27 +1,80 @@ import Foundation import SoraFoundation +import BigInt protocol ReferendumLockChangeViewModelFactoryProtocol { func createTransferableAmountViewModel( - from diff: GovernanceLockStateDiff, + resultLocked: BigUInt?, balance: AssetBalance, locks: AssetLocks, locale: Locale ) -> ReferendumLockTransitionViewModel? func createAmountViewModel( - from diff: GovernanceLockStateDiff, + initLocked: BigUInt, + resultLocked: BigUInt?, locale: Locale ) -> ReferendumLockTransitionViewModel? func createPeriodViewModel( - from diff: GovernanceLockStateDiff, + initLockedUntil: BlockNumber, + resultLockedUntil: BlockNumber?, blockNumber: BlockNumber, blockTime: BlockTime, locale: Locale ) -> ReferendumLockTransitionViewModel? } +extension ReferendumLockChangeViewModelFactoryProtocol { + func createTransferableAmountViewModel( + from diff: GovernanceLockStateDiff, + balance: AssetBalance, + locks: AssetLocks, + locale: Locale + ) -> ReferendumLockTransitionViewModel? { + createTransferableAmountViewModel( + resultLocked: diff.after?.maxLockedAmount, + balance: balance, + locks: locks, + locale: locale + ) + } + + func createAmountViewModel( + from diff: GovernanceLockStateDiff, + locale: Locale + ) -> ReferendumLockTransitionViewModel? { + createAmountViewModel( + initLocked: diff.before.maxLockedAmount, + resultLocked: diff.after?.maxLockedAmount, + locale: locale + ) + } + + func createPeriodViewModel( + from diff: GovernanceLockStateDiff, + blockNumber: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumLockTransitionViewModel? { + let resultLockedUntil: BlockNumber? + + if let toState = diff.after { + resultLockedUntil = toState.lockedUntil ?? blockNumber + } else { + resultLockedUntil = nil + } + + return createPeriodViewModel( + initLockedUntil: diff.before.lockedUntil ?? blockNumber, + resultLockedUntil: resultLockedUntil, + blockNumber: blockNumber, + blockTime: blockTime, + locale: locale + ) + } +} + final class ReferendumLockChangeViewModelFactory { let balanceFormatter: LocalizableResource let amountFormatter: LocalizableResource @@ -42,7 +95,7 @@ final class ReferendumLockChangeViewModelFactory { extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol { func createTransferableAmountViewModel( - from diff: GovernanceLockStateDiff, + resultLocked: BigUInt?, balance: AssetBalance, locks: AssetLocks, locale: Locale @@ -61,13 +114,13 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac let balanceFormatter = balanceFormatter.value(for: locale) - if let toState = diff.after { + if let resultLocked = resultLocked { let otherLocks = locks .filter { $0.identifier != votingLockId } .map(\.amount) .max() ?? 0 - let newLocked = max(otherLocks, toState.maxLockedAmount) + let newLocked = max(otherLocks, resultLocked) let newTransferable = balance.newTransferable(for: newLocked) @@ -100,12 +153,13 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac } func createAmountViewModel( - from diff: GovernanceLockStateDiff, + initLocked: BigUInt, + resultLocked: BigUInt?, locale: Locale ) -> ReferendumLockTransitionViewModel? { guard let fromAmountDecimal = Decimal.fromSubstrateAmount( - diff.before.maxLockedAmount, + initLocked, precision: assetDisplayInfo.assetPrecision ), let fromAmountString = amountFormatter.value(for: locale).stringFromDecimal(fromAmountDecimal) else { @@ -117,10 +171,10 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac let balanceFormatter = balanceFormatter.value(for: locale) - if let toState = diff.after { + if let resultLocked = resultLocked { guard let toAmountDecimal = Decimal.fromSubstrateAmount( - toState.maxLockedAmount, + resultLocked, precision: assetDisplayInfo.assetPrecision ) else { return nil @@ -147,12 +201,13 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac } func createPeriodViewModel( - from diff: GovernanceLockStateDiff, + initLockedUntil: BlockNumber, + resultLockedUntil: BlockNumber?, blockNumber: BlockNumber, blockTime: BlockTime, locale: Locale ) -> ReferendumLockTransitionViewModel? { - let fromBlock = max(diff.before.lockedUntil ?? blockNumber, blockNumber) + let fromBlock = max(initLockedUntil, blockNumber) let fromPeriod = blockNumber.secondsTo(block: fromBlock, blockDuration: blockTime) let fromPeriodString = fromPeriod.localizedDaysHoursIncludingZero(for: locale) @@ -160,8 +215,8 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac let toPeriodString: String let change: ReferendumLockTransitionViewModel.Change? - if let toState = diff.after { - let toBlock = max(toState.lockedUntil ?? blockNumber, blockNumber) + if let resultLockedUntil = resultLockedUntil { + let toBlock = max(resultLockedUntil, blockNumber) let toPeriod = blockNumber.secondsTo(block: toBlock, blockDuration: blockTime) toPeriodString = toPeriod.localizedDaysHoursIncludingZero(for: locale) From 2880008e10cd4d0ab0a6753a234bb1b2eba364f9 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 3 Nov 2022 12:30:03 +0500 Subject: [PATCH 148/229] unlock confirm --- novawallet/Common/Model/BalanceLockType.swift | 3 +- .../Model/ChainRegistry/ChainModel.swift | 8 ++ .../GovernanceUnlockInteractor.swift | 4 +- .../GovernanceUnlockConfirmInteractor.swift | 32 ++++-- .../GovernanceUnlockConfirmPresenter.swift | 87 ++++++++++++--- .../GovernanceUnlockConfirmProtocols.swift | 6 +- ...overnanceUnlockConfirmViewController.swift | 48 +++++++- .../GovernanceUnlockConfirmViewFactory.swift | 104 +++++++++++++++++- .../GovernanceUnlockConfirmViewLayout.swift | 2 + .../GovernanceUnlockConfirmWireframe.swift | 2 +- .../GovernanceUnlockSetupPresenter.swift | 16 ++- .../GovernanceUnlockSetupProtocols.swift | 9 +- .../GovernanceUnlockSetupViewFactory.swift | 8 +- .../GovernanceUnlockSetupWireframe.swift | 26 ++++- .../Operation/Gov2ExtrinsicFactory.swift | 2 +- .../ReferendumVoteConfirmViewLayout.swift | 2 + .../ReferendumVoteConfirmWireframe.swift | 13 +-- ...ReferendumLockChangeViewModelFactory.swift | 45 +++++++- novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 20 files changed, 367 insertions(+), 52 deletions(-) diff --git a/novawallet/Common/Model/BalanceLockType.swift b/novawallet/Common/Model/BalanceLockType.swift index 8eb19e293c..66490654c8 100644 --- a/novawallet/Common/Model/BalanceLockType.swift +++ b/novawallet/Common/Model/BalanceLockType.swift @@ -6,6 +6,7 @@ enum LockType: String { case vesting case democracy = "democrac" case elections = "phrelect" + case governance = "pyconvot" static var locksOrder: [Self] = [.vesting, .staking, .democracy, .elections] @@ -20,7 +21,7 @@ enum LockType: String { return R.string.localizable.stakingTitle( preferredLanguages: locale.rLanguages ) - case .democracy: + case .democracy, .governance: return R.string.localizable.walletAccountLocksDemocracy( preferredLanguages: locale.rLanguages ) diff --git a/novawallet/Common/Model/ChainRegistry/ChainModel.swift b/novawallet/Common/Model/ChainRegistry/ChainModel.swift index 5df5c38109..e360aa6b25 100644 --- a/novawallet/Common/Model/ChainRegistry/ChainModel.swift +++ b/novawallet/Common/Model/ChainRegistry/ChainModel.swift @@ -137,6 +137,14 @@ struct ChainModel: Equatable, Codable, Hashable { utilityAsset()?.displayInfo(with: icon) } + func utilityChainAssetId() -> ChainAssetId? { + guard let utilityAsset = utilityAssets().first else { + return nil + } + + return ChainAssetId(chainId: chainId, assetId: utilityAsset.assetId) + } + var typesUsage: TypesUsage { if let types = types { return types.overridesCommon ? .onlyOwn : .both diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift index 3f4982793b..62d6195007 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift @@ -32,7 +32,8 @@ class GovernanceUnlockInteractor: GovernanceUnlockInteractorInputProtocol, AnyCa blockTimeService: BlockTimeEstimationServiceProtocol, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, - operationQueue: OperationQueue + operationQueue: OperationQueue, + currencyManager: CurrencyManagerProtocol ) { self.chain = chain self.selectedAccount = selectedAccount @@ -44,6 +45,7 @@ class GovernanceUnlockInteractor: GovernanceUnlockInteractorInputProtocol, AnyCa self.connection = connection self.runtimeProvider = runtimeProvider self.operationQueue = operationQueue + self.currencyManager = currencyManager } deinit { diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift index 8028d2059e..f883398d1d 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift @@ -36,7 +36,8 @@ final class GovernanceUnlockConfirmInteractor: GovernanceUnlockInteractor, AnyPr blockTimeService: BlockTimeEstimationServiceProtocol, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, - operationQueue: OperationQueue + operationQueue: OperationQueue, + currencyManager: CurrencyManagerProtocol ) { self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.extrinsicFactory = extrinsicFactory @@ -53,7 +54,8 @@ final class GovernanceUnlockConfirmInteractor: GovernanceUnlockInteractor, AnyPr blockTimeService: blockTimeService, connection: connection, runtimeProvider: runtimeProvider, - operationQueue: operationQueue + operationQueue: operationQueue, + currencyManager: currencyManager ) } @@ -85,7 +87,9 @@ final class GovernanceUnlockConfirmInteractor: GovernanceUnlockInteractor, AnyPr ) } - private func createExtrinsicBuilderClosure(for actions: Set) -> ExtrinsicBuilderClosure { + private func createExtrinsicBuilderClosure( + for actions: Set + ) -> ExtrinsicBuilderClosure { { [weak self] builder in guard let strongSelf = self else { return builder @@ -99,16 +103,21 @@ final class GovernanceUnlockConfirmInteractor: GovernanceUnlockInteractor, AnyPr } } + private func makeSubscription() { + clearAndSubscribeBalance() + clearAndSubscribeLocks() + } + override func setup() { super.setup() - clearAndSubscribeLocks() + makeSubscription() } override func remakeSubscriptions() { super.remakeSubscriptions() - clearAndSubscribeLocks() + makeSubscription() } } @@ -160,10 +169,15 @@ extension GovernanceUnlockConfirmInteractor: WalletLocalStorageSubscriber, Walle func handleAssetBalance( result: Result, - accountId: AccountId, - chainId: ChainModel.Id, - assetId: AssetModel.Id + accountId _: AccountId, + chainId _: ChainModel.Id, + assetId _: AssetModel.Id ) { - + switch result { + case let .success(changes): + presenter?.didReceiveBalance(changes) + case let .failure(error): + presenter?.didReceiveError(.balanceSubscriptionFailed(error)) + } } } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift index 19649254c0..45f0d1f6d4 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift @@ -15,7 +15,7 @@ final class GovernanceUnlockConfirmPresenter { let dataValidatingFactory: GovernanceValidatorFactoryProtocol let logger: LoggerProtocol - private var votingResult: CallbackStorageSubscriptionResult? + private var votingResult: CallbackStorageSubscriptionResult private var unlockSchedule: GovernanceUnlockSchedule private var locks: AssetLocks? private var assetBalance: AssetBalance? @@ -31,6 +31,7 @@ final class GovernanceUnlockConfirmPresenter { wireframe: GovernanceUnlockConfirmWireframeProtocol, chain: ChainModel, selectedAccount: MetaChainAccountResponse, + votingResult: CallbackStorageSubscriptionResult, schedule: GovernanceUnlockSchedule, blockNumber: BlockNumber, balanceViewModelFactory: BalanceViewModelFactoryProtocol, @@ -43,7 +44,8 @@ final class GovernanceUnlockConfirmPresenter { self.wireframe = wireframe self.chain = chain self.selectedAccount = selectedAccount - self.unlockSchedule = schedule + self.votingResult = votingResult + unlockSchedule = schedule self.blockNumber = blockNumber self.balanceViewModelFactory = balanceViewModelFactory self.lockChangeViewModelFactory = lockChangeViewModelFactory @@ -109,12 +111,8 @@ final class GovernanceUnlockConfirmPresenter { } } - private func provideTransferableViewModel() { - - } - private func provideChangesViewModels() { - guard let tracksVoting = votingResult?.value else { + guard let tracksVoting = votingResult.value else { return } @@ -142,6 +140,20 @@ final class GovernanceUnlockConfirmPresenter { ) { view?.didReceiveTransferableAmount(viewModel: transferableViewModel) } + + if let locks = locks, let chainAssetId = chain.utilityChainAssetId() { + let remainedLocksViewModel = lockChangeViewModelFactory.createRemainedLockViewModel( + after: remainedLocked, + chainAssetId: chainAssetId, + accountId: selectedAccount.chainAccount.accountId, + locks: locks, + locale: selectedLocale + ) + + view?.didReceiveRemainedLock(viewModel: remainedLocksViewModel) + } else { + view?.didReceiveRemainedLock(viewModel: nil) + } } private func updateView() { @@ -171,7 +183,7 @@ final class GovernanceUnlockConfirmPresenter { } private func refreshUnlockSchedule() { - guard let tracksVoting = votingResult?.value else { + guard let tracksVoting = votingResult.value else { return } @@ -187,6 +199,55 @@ extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmPresenterProt refreshFee() } + + func confirm() { + guard let assetInfo = chain.utilityAssetDisplayInfo() else { + return + } + + DataValidationRunner( + validators: [ + dataValidatingFactory.hasInPlank( + fee: fee, + locale: selectedLocale, + precision: assetInfo.assetPrecision + ) { [weak self] in + self?.refreshFee() + }, + dataValidatingFactory.canPayFeeInPlank( + balance: assetBalance?.transferable, + fee: fee, + asset: assetInfo, + locale: selectedLocale + ) + ] + ).runValidation { [weak self] in + guard + let blockNumber = self?.blockNumber, + let actions = self?.unlockSchedule.availableUnlock(at: blockNumber).actions, + !actions.isEmpty else { + return + } + + self?.view?.didStartLoading() + self?.interactor.unlock(using: actions) + } + } + + func presentSenderDetails() { + guard + let address = try? selectedAccount.chainAccount.accountId.toAddress(using: chain.chainFormat), + let view = view else { + return + } + + wireframe.presentAccountOptions( + from: view, + address: address, + chain: chain, + locale: selectedLocale + ) + } } extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmInteractorOutputProtocol { @@ -202,7 +263,7 @@ extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmInteractorOut provideChangesViewModels() } - func didReceiveUnlockHash(_ hash: String) { + func didReceiveUnlockHash(_: String) { view?.didStopLoading() wireframe.presentExtrinsicSubmission(from: view, completionAction: .dismiss, locale: selectedLocale) @@ -238,7 +299,7 @@ extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmInteractorOut } func didReceiveVoting(_ result: CallbackStorageSubscriptionResult) { - self.votingResult = result + votingResult = result if let tracksVoting = result.value { interactor.refreshUnlockSchedule(for: tracksVoting, blockHash: result.blockHash) @@ -249,7 +310,7 @@ extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmInteractorOut func didReceiveUnlockSchedule(_ schedule: GovernanceUnlockSchedule) { if schedule != unlockSchedule { - self.unlockSchedule = schedule + unlockSchedule = schedule provideChangesViewModels() provideAmountViewModel() @@ -258,7 +319,7 @@ extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmInteractorOut } func didReceiveBlockNumber(_ block: BlockNumber) { - self.blockNumber = block + blockNumber = block provideFeeViewModel() @@ -267,7 +328,7 @@ extension GovernanceUnlockConfirmPresenter: GovernanceUnlockConfirmInteractorOut refreshUnlockSchedule() } - func didReceiveBlockTime(_ time: BlockTime) {} + func didReceiveBlockTime(_: BlockTime) {} func didReceivePrice(_ price: PriceData?) { self.price = price diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift index a9f3469b47..7b09765b5c 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmProtocols.swift @@ -12,6 +12,8 @@ protocol GovernanceUnlockConfirmViewProtocol: ControllerBackedProtocol, Loadable protocol GovernanceUnlockConfirmPresenterProtocol: AnyObject { func setup() + func confirm() + func presentSenderDetails() } protocol GovernanceUnlockConfirmInteractorInputProtocol: GovernanceUnlockInteractorInputProtocol { @@ -28,5 +30,5 @@ protocol GovernanceUnlockConfirmInteractorOutputProtocol: GovernanceUnlockIntera } protocol GovernanceUnlockConfirmWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, - FeeRetryable, MessageSheetPresentable, AddressOptionsPresentable, - ExtrinsicSubmissionPresenting, GovernanceErrorPresentable {} + FeeRetryable, MessageSheetPresentable, AddressOptionsPresentable, + ExtrinsicSubmissionPresenting, GovernanceErrorPresentable {} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift index 1609c5ceb5..7ef3542774 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift @@ -28,11 +28,22 @@ final class GovernanceUnlockConfirmViewController: UIViewController, ViewHolder override func viewDidLoad() { super.viewDidLoad() + setupHandlers() setupLocalization() presenter.setup() } + private func setupHandlers() { + rootView.accountCell.addTarget(self, action: #selector(actionSender), for: .touchUpInside) + + rootView.actionLoadableView.actionButton.addTarget( + self, + action: #selector(actionConfirm), + for: .touchUpInside + ) + } + private func setupLocalization() { let languages = selectedLocale.rLanguages @@ -59,6 +70,14 @@ final class GovernanceUnlockConfirmViewController: UIViewController, ViewHolder rootView.actionLoadableView.actionButton.imageWithTitleView?.title = R.string.localizable .commonConfirm(preferredLanguages: selectedLocale.rLanguages) } + + @objc private func actionConfirm() { + presenter.confirm() + } + + @objc private func actionSender() { + presenter.presentSenderDetails() + } } extension GovernanceUnlockConfirmViewController: GovernanceUnlockConfirmViewProtocol { @@ -88,9 +107,34 @@ extension GovernanceUnlockConfirmViewController: GovernanceUnlockConfirmViewProt func didReceiveRemainedLock(viewModel: GovernanceRemainedLockViewModel?) { if let viewModel = viewModel { - + let amountString = NSMutableAttributedString( + string: viewModel.amount, + attributes: [ + .foregroundColor: R.color.colorWhite()!, + .font: UIFont.caption1 + ] + ) + + let remainingLocksString = viewModel.modules + .map { $0.firstLetterCapitalized() } + .joined(separator: ", ") + + let remainingLocksAttributedString = NSAttributedString( + string: R.string.localizable.govRemainsLockedSuffix( + remainingLocksString, + preferredLanguages: selectedLocale.rLanguages + ), + attributes: [ + .foregroundColor: R.color.colorTransparentText()!, + .font: UIFont.caption1 + ] + ) + + amountString.append(remainingLocksAttributedString) + + rootView.hintsView.bind(attributedTexts: [amountString]) } else { - rootView.hintsView.bind(texts: [""]) + rootView.hintsView.bind(attributedTexts: []) } } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift index 62d81fdaa8..e98b95111d 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift @@ -1,21 +1,119 @@ import Foundation +import RobinHood +import SoraFoundation struct GovernanceUnlockConfirmViewFactory { static func createView( for state: GovernanceSharedState, + votingResult: CallbackStorageSubscriptionResult, schedule: GovernanceUnlockSchedule, blockNumber: BlockNumber ) -> GovernanceUnlockConfirmViewProtocol? { - let interactor = GovernanceUnlockConfirmInteractor() + guard + let wallet = SelectedWalletSettings.shared.value, + let chain = state.settings.value, + let selectedAccount = wallet.fetchMetaChainAccount(for: chain.accountRequest()), + let interactor = createInteractor(for: state, chain: chain, selectedAccount: selectedAccount), + let assetInfo = chain.utilityAssetDisplayInfo(), + let currencyManager = CurrencyManager.shared else { + return nil + } + let wireframe = GovernanceUnlockConfirmWireframe() - let presenter = GovernanceUnlockConfirmPresenter(interactor: interactor, wireframe: wireframe) + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: assetInfo, + priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) + ) + + let localizationManager = LocalizationManager.shared + + let lockChangeViewModelFactory = ReferendumLockChangeViewModelFactory( + assetDisplayInfo: assetInfo, + votingLockId: ConvictionVoting.lockId + ) + + let dataValidatingFactory = GovernanceValidatorFactory( + presentable: wireframe, + assetBalanceFormatterFactory: AssetBalanceFormatterFactory(), + quantityFormatter: NumberFormatter.quantity.localizableResource() + ) - let view = GovernanceUnlockConfirmViewController(presenter: presenter) + let presenter = GovernanceUnlockConfirmPresenter( + interactor: interactor, + wireframe: wireframe, + chain: chain, + selectedAccount: selectedAccount, + votingResult: votingResult, + schedule: schedule, + blockNumber: blockNumber, + balanceViewModelFactory: balanceViewModelFactory, + lockChangeViewModelFactory: lockChangeViewModelFactory, + dataValidatingFactory: dataValidatingFactory, + localizationManager: localizationManager, + logger: Logger.shared + ) + + let view = GovernanceUnlockConfirmViewController( + presenter: presenter, + localizationManager: localizationManager + ) presenter.view = view + dataValidatingFactory.view = view interactor.presenter = presenter return view } + + private static func createInteractor( + for state: GovernanceSharedState, + chain: ChainModel, + selectedAccount: MetaChainAccountResponse + ) -> GovernanceUnlockConfirmInteractor? { + guard + let connection = state.chainRegistry.getConnection(for: chain.chainId), + let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId), + let subscriptionFactory = state.subscriptionFactory, + let blockTimeService = state.blockTimeService, + let currencyManager = CurrencyManager.shared else { + return nil + } + + let lockStateFactory = Gov2LockStateFactory( + requestFactory: state.requestFactory, + unlocksCalculator: Gov2UnlocksCalculator() + ) + + let operationQueue = OperationManagerFacade.sharedDefaultQueue + + let extrinsicService = ExtrinsicServiceFactory( + runtimeRegistry: runtimeProvider, + engine: connection, + operationManager: OperationManager(operationQueue: operationQueue) + ).createService(account: selectedAccount.chainAccount, chain: chain) + + let signer = SigningWrapperFactory().createSigningWrapper( + for: selectedAccount.metaId, + accountResponse: selectedAccount.chainAccount + ) + + return .init( + chain: chain, + selectedAccount: selectedAccount, + subscriptionFactory: subscriptionFactory, + lockStateFactory: lockStateFactory, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, + extrinsicFactory: Gov2ExtrinsicFactory(), + extrinsicService: extrinsicService, + signer: signer, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, + blockTimeService: blockTimeService, + connection: connection, + runtimeProvider: runtimeProvider, + operationQueue: operationQueue, + currencyManager: currencyManager + ) + } } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift index de1327056c..2a1da42035 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewLayout.swift @@ -87,6 +87,8 @@ final class GovernanceUnlockConfirmViewLayout: UIView { changesTableView.addArrangedSubview(transferableCell) changesTableView.addArrangedSubview(lockedAmountCell) + containerView.stackView.setCustomSpacing(16.0, after: changesTableView) + containerView.stackView.addArrangedSubview(hintsView) } } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmWireframe.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmWireframe.swift index 88c57355ed..54af173de7 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmWireframe.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmWireframe.swift @@ -1,3 +1,3 @@ import Foundation -final class GovernanceUnlockConfirmWireframe: GovernanceUnlockConfirmWireframeProtocol {} \ No newline at end of file +final class GovernanceUnlockConfirmWireframe: GovernanceUnlockConfirmWireframeProtocol, ModalAlertPresenting {} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift index a4a6845609..db3da83b20 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift @@ -243,7 +243,21 @@ extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupPresenterProtocol interactor.setup() } - func unlock() {} + func unlock() { + guard + let votingResult = votingResult, + let unlockSchedule = unlockSchedule, + let blockNumber = blockNumber else { + return + } + + wireframe.showConfirm( + from: view, + votingResult: votingResult, + schedule: unlockSchedule, + blockNumber: blockNumber + ) + } } extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift index 936487f818..c36799ef83 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift @@ -12,4 +12,11 @@ protocol GovernanceUnlockSetupInteractorInputProtocol: GovernanceUnlockInteracto protocol GovernanceUnlockSetupInteractorOutputProtocol: GovernanceUnlockInteractorOutputProtocol {} -protocol GovernanceUnlockSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable {} +protocol GovernanceUnlockSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable { + func showConfirm( + from view: GovernanceUnlockSetupViewProtocol?, + votingResult: CallbackStorageSubscriptionResult, + schedule: GovernanceUnlockSchedule, + blockNumber: BlockNumber + ) +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift index 9456ca8407..bd672a0eff 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift @@ -10,7 +10,7 @@ struct GovernanceUnlockSetupViewFactory { return nil } - let wireframe = GovernanceUnlockSetupWireframe() + let wireframe = GovernanceUnlockSetupWireframe(state: state) let balanceViewModelFactory = BalanceViewModelFactory( targetAssetInfo: assetInfo, @@ -40,7 +40,8 @@ struct GovernanceUnlockSetupViewFactory { guard let wallet = SelectedWalletSettings.shared.value, let chain = state.settings.value, - let selectedAccount = wallet.fetchMetaChainAccount(for: chain.accountRequest()) else { + let selectedAccount = wallet.fetchMetaChainAccount(for: chain.accountRequest()), + let currencyManager = CurrencyManager.shared else { return nil } @@ -67,7 +68,8 @@ struct GovernanceUnlockSetupViewFactory { blockTimeService: blockTimeService, connection: connection, runtimeProvider: runtimeProvider, - operationQueue: OperationManagerFacade.sharedDefaultQueue + operationQueue: OperationManagerFacade.sharedDefaultQueue, + currencyManager: currencyManager ) } } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift index 42edfea76d..3d7089d07a 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift @@ -1,3 +1,27 @@ import Foundation -final class GovernanceUnlockSetupWireframe: GovernanceUnlockSetupWireframeProtocol {} +final class GovernanceUnlockSetupWireframe: GovernanceUnlockSetupWireframeProtocol { + let state: GovernanceSharedState + + init(state: GovernanceSharedState) { + self.state = state + } + + func showConfirm( + from view: GovernanceUnlockSetupViewProtocol?, + votingResult: CallbackStorageSubscriptionResult, + schedule: GovernanceUnlockSchedule, + blockNumber: BlockNumber + ) { + guard let confirmView = GovernanceUnlockConfirmViewFactory.createView( + for: state, + votingResult: votingResult, + schedule: schedule, + blockNumber: blockNumber + ) else { + return + } + + view?.controller.navigationController?.pushViewController(confirmView.controller, animated: true) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift index abf8b94ed1..da85192454 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift @@ -29,7 +29,7 @@ final class Gov2ExtrinsicFactory: GovernanceExtrinsicFactoryProtocol { ) throws -> ExtrinsicBuilderProtocol { let removeVoteCalls: [RuntimeCall] = actions.compactMap { action in switch action { - case .unvote(let track, let index): + case let .unvote(track, index): return ConvictionVoting.RemoveVoteCall( track: Referenda.TrackId(track), index: Referenda.ReferendumIndex(index) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift index c168ff462e..94a90ac695 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewLayout.swift @@ -101,6 +101,8 @@ final class ReferendumVoteConfirmViewLayout: UIView { changesTableView.addArrangedSubview(lockedAmountCell) changesTableView.addArrangedSubview(lockedPeriodCell) + containerView.stackView.setCustomSpacing(16.0, after: changesTableView) + containerView.stackView.addArrangedSubview(hintsView) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift index cd1802af30..4b1e48148d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmWireframe.swift @@ -1,14 +1,3 @@ import Foundation -final class ReferendumVoteConfirmWireframe: ReferendumVoteConfirmWireframeProtocol, ModalAlertPresenting { - func complete(on view: ReferendumVoteConfirmViewProtocol?, locale: Locale) { - let title = R.string.localizable - .commonTransactionSubmitted(preferredLanguages: locale.rLanguages) - - let presenter = view?.controller.navigationController?.presentingViewController - - presenter?.dismiss(animated: true) { [weak self] in - self?.presentSuccessNotification(title, from: presenter, completion: nil) - } - } -} +final class ReferendumVoteConfirmWireframe: ReferendumVoteConfirmWireframeProtocol, ModalAlertPresenting {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift index 83051f7f48..87c1b61dbe 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift @@ -23,6 +23,14 @@ protocol ReferendumLockChangeViewModelFactoryProtocol { blockTime: BlockTime, locale: Locale ) -> ReferendumLockTransitionViewModel? + + func createRemainedLockViewModel( + after remainedGovernanceLock: BigUInt, + chainAssetId: ChainAssetId, + accountId: AccountId, + locks: AssetLocks, + locale: Locale + ) -> GovernanceRemainedLockViewModel? } extension ReferendumLockChangeViewModelFactoryProtocol { @@ -94,6 +102,41 @@ final class ReferendumLockChangeViewModelFactory { } extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol { + func createRemainedLockViewModel( + after remainedGovernanceLock: BigUInt, + chainAssetId: ChainAssetId, + accountId: AccountId, + locks: AssetLocks, + locale: Locale + ) -> GovernanceRemainedLockViewModel? { + let otherLocks = locks.filter { $0.displayId != votingLockId } + + let newLock = AssetLock( + chainAssetId: chainAssetId, + accountId: accountId, + type: votingLockId.data(using: .utf8) ?? Data(), + amount: remainedGovernanceLock + ) + + let newLocks = (otherLocks + [newLock]).sorted { $0.amount > $1.amount } + + if let lockedAmount = newLocks.first?.amount, lockedAmount > 0 { + let amountDecimal = Decimal.fromSubstrateAmount( + lockedAmount, + precision: assetDisplayInfo.assetPrecision + ) ?? 0 + + let balanceFormatter = balanceFormatter.value(for: locale) + let amountString = balanceFormatter.stringFromDecimal(amountDecimal) ?? "" + + let types = newLocks.map { $0.lockType?.displayType.value(for: locale) ?? $0.displayId ?? "" } + + return .init(amount: amountString, modules: types) + } else { + return nil + } + } + func createTransferableAmountViewModel( resultLocked: BigUInt?, balance: AssetBalance, @@ -116,7 +159,7 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac if let resultLocked = resultLocked { let otherLocks = locks - .filter { $0.identifier != votingLockId } + .filter { $0.displayId != votingLockId } .map(\.amount) .max() ?? 0 diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index f5e66f29aa..446040a889 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1075,3 +1075,4 @@ "gov.in.queue.counter" = "(%@ of %@)"; "common.unlock" = "Unlock"; "common.unlockable" = "Unlockable"; +"gov.remains.locked.suffix" = " remains locked in %@"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 850ec503dc..d3096dff3d 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1076,3 +1076,4 @@ "gov.in.queue.counter" = "(%@ из %@)"; "common.unlock" = "Разблокировать"; "common.unlockable" = "Разблокируемые"; +"gov.remains.locked.suffix" = " остаются заблокированны в %@"; From 5935c01ed9a714de42fbc438821067ac644bfd00 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 3 Nov 2022 16:43:37 +0500 Subject: [PATCH 149/229] make unlock flow important --- novawallet.xcodeproj/project.pbxproj | 4 ++++ novawallet/Common/Model/ChainRegistry/ChainModel.swift | 3 ++- .../GovernanceUnlockConfirmViewController.swift | 2 +- .../Vote/Governance/Operation/Gov1OperationFactory.swift | 9 +++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index f36f1563f7..16cab58205 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -740,6 +740,7 @@ 8436EDE225895804004D9E97 /* RampProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8436EDE125895804004D9E97 /* RampProvider.swift */; }; 8436EDE725895846004D9E97 /* PurchaseProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8436EDE625895846004D9E97 /* PurchaseProvider.swift */; }; 8436EDEF25896722004D9E97 /* PurchaseAggregator+Default.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8436EDEE25896722004D9E97 /* PurchaseAggregator+Default.swift */; }; + 8438432E2913B3150048595C /* Gov1OperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8438432D2913B3150048595C /* Gov1OperationFactory.swift */; }; 8438C45B2655AC2600047E3F /* runtime-rococo.json in Resources */ = {isa = PBXBuildFile; fileRef = 8438C45A2655AC2600047E3F /* runtime-rococo.json */; }; 8438E1D224BFAAD2001BDB13 /* JSONRPCTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8438E1D124BFAAD2001BDB13 /* JSONRPCTests.swift */; }; 843910B0253ED36C00E3C217 /* ChainStorageItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843910AF253ED36C00E3C217 /* ChainStorageItem.swift */; }; @@ -3686,6 +3687,7 @@ 8436EDE125895804004D9E97 /* RampProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RampProvider.swift; sourceTree = ""; }; 8436EDE625895846004D9E97 /* PurchaseProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseProvider.swift; sourceTree = ""; }; 8436EDEE25896722004D9E97 /* PurchaseAggregator+Default.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PurchaseAggregator+Default.swift"; sourceTree = ""; }; + 8438432D2913B3150048595C /* Gov1OperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1OperationFactory.swift; sourceTree = ""; }; 8438C45A2655AC2600047E3F /* runtime-rococo.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "runtime-rococo.json"; sourceTree = ""; }; 8438E1CF24BFAAD2001BDB13 /* novawalletIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = novawalletIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8438E1D124BFAAD2001BDB13 /* JSONRPCTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONRPCTests.swift; sourceTree = ""; }; @@ -10319,6 +10321,7 @@ 843461F1290D370000379936 /* Locks */, 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */, 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, + 8438432D2913B3150048595C /* Gov1OperationFactory.swift */, 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */, 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */, @@ -16367,6 +16370,7 @@ 8423ADD226B2C9D000057EDD /* ImportantViewProtocol.swift in Sources */, 84A3B8A62836E08600DE2669 /* CollatorSelectionInfo.swift in Sources */, 841E5569282EAC2600C8438F /* ParachainStakingNoStakingState.swift in Sources */, + 8438432E2913B3150048595C /* Gov1OperationFactory.swift in Sources */, 84CFF1E926526FBC00DB7CF7 /* StakingBondMoreWireframe.swift in Sources */, 84D17ECE2804290700F7BAFF /* RadioSelectorView.swift in Sources */, 841E5567282EAC1000C8438F /* ParachainStakingInitState.swift in Sources */, diff --git a/novawallet/Common/Model/ChainRegistry/ChainModel.swift b/novawallet/Common/Model/ChainRegistry/ChainModel.swift index e360aa6b25..1a1b46ea9e 100644 --- a/novawallet/Common/Model/ChainRegistry/ChainModel.swift +++ b/novawallet/Common/Model/ChainRegistry/ChainModel.swift @@ -120,7 +120,7 @@ struct ChainModel: Equatable, Codable, Hashable { } var hasGovernance: Bool { - options?.contains(.governance) ?? false + options?.contains(where: { $0 == .governance || $0 == .governanceV1 }) ?? false } var isRelaychain: Bool { parentId == nil } @@ -171,4 +171,5 @@ enum ChainOptions: String, Codable { case testnet case crowdloans case governance + case governanceV1 = "governance-v1" } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift index 7ef3542774..3b653b65f3 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift @@ -1,7 +1,7 @@ import UIKit import SoraFoundation -final class GovernanceUnlockConfirmViewController: UIViewController, ViewHolder { +final class GovernanceUnlockConfirmViewController: UIViewController, ViewHolder, ImportantViewProtocol { typealias RootViewType = GovernanceUnlockConfirmViewLayout let presenter: GovernanceUnlockConfirmPresenterProtocol diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift new file mode 100644 index 0000000000..c4554ce972 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift @@ -0,0 +1,9 @@ +// +// Gov1OperationFactory.swift +// novawallet +// +// Created by Ruslan Rezin on 03.11.2022. +// Copyright © 2022 Nova Foundation. All rights reserved. +// + +import Foundation From e84bbe7c78a2f680f7f8984485a3bfcfcb9fc75e Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 3 Nov 2022 18:20:19 +0300 Subject: [PATCH 150/229] added full description --- novawallet.xcodeproj/project.pbxproj | 73 +++- .../xcshareddata/swiftpm/Package.resolved | 23 + .../ReferendumDetailsPresenter.swift | 4 +- .../ReferendumDetailsProtocols.swift | 2 + .../ReferendumDetailsWireframe.swift | 14 + .../View/ReferendumDetailsTitleView.swift | 39 +- .../Markdownosaur.swift | 413 ++++++++++++++++++ .../ReferendumFullDescriptionInteractor.swift | 7 + .../ReferendumFullDescriptionPresenter.swift | 21 + .../ReferendumFullDescriptionProtocols.swift | 11 + ...erendumFullDescriptionViewController.swift | 49 +++ ...ReferendumFullDescriptionViewFactory.swift | 17 + .../ReferendumFullDescriptionViewLayout.swift | 55 +++ .../ReferendumFullDescriptionWireframe.swift | 3 + .../ReferendumFullDescription/test.md | 287 ++++++++++++ 15 files changed, 986 insertions(+), 32 deletions(-) create mode 100644 novawallet.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionInteractor.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionWireframe.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/test.md diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 5c06921b7b..2deed008f6 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -55,6 +55,7 @@ 163709FEE6203813261DD771 /* ReferendumVoteConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3531B386DEF40108C34E7232 /* ReferendumVoteConfirmViewLayout.swift */; }; 16FAE3C58B34D700D8A7A217 /* DAppListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E6E41F045986002E1E26C12 /* DAppListWireframe.swift */; }; 1710F415F6AC7BBC622F4BD2 /* ParaStkSelectCollatorsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC320A5EC0D18B6F443BB2E /* ParaStkSelectCollatorsInteractor.swift */; }; + 1752940C07D7BA41801E3853 /* ReferendumFullDescriptionInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E47548C4A216327B05A63C /* ReferendumFullDescriptionInteractor.swift */; }; 1795E946F1E386442E96E2BC /* StakingPayoutConfirmationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C0AC11A4A195BB697578CE /* StakingPayoutConfirmationPresenter.swift */; }; 1812D5012A1765CB38D32A4A /* WalletsListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6E67AD564867E121601F18 /* WalletsListPresenter.swift */; }; 187C300E406092FA5F682A61 /* LedgerPerformOperationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FD612D8F897463726CDD033 /* LedgerPerformOperationViewController.swift */; }; @@ -159,6 +160,7 @@ 37E229641DCDF64AC5AF1DCD /* DAppBrowserPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF860B3465854DCBC02DFB3 /* DAppBrowserPresenter.swift */; }; 38D0977931828C7894579968 /* GovernanceUnlockSetupInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFA54AB88E24A2053F289D74 /* GovernanceUnlockSetupInteractor.swift */; }; 39218CF5AA701518BD3B0103 /* ExportMnemonicInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200C6B2C85846AED8CA9451A /* ExportMnemonicInteractor.swift */; }; + 3A4743C7C74BE4F74F6390F6 /* ReferendumFullDescriptionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D087F5710630FCC968B65FB5 /* ReferendumFullDescriptionViewLayout.swift */; }; 3AD7635AFA1F7E66A3C00F56 /* ParitySignerAddressesInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF715CEF29477B59119520F1 /* ParitySignerAddressesInteractor.swift */; }; 3B6F50061AD9FC31D6712D9F /* ParaStkCollatorsSearchProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CFD9A58CDDA60D9E1204078 /* ParaStkCollatorsSearchProtocols.swift */; }; 3B7EEC888C19F954B5EB1012 /* OnChainTransferSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9871C4FF3B05F6055AF82F14 /* OnChainTransferSetupWireframe.swift */; }; @@ -248,6 +250,7 @@ 61B9688494251703A6373A1B /* StakingAmountWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6216F6F1B91F798F07695FB6 /* StakingAmountWireframe.swift */; }; 61E0DC83C1D60D677274D7CE /* AccountExportPasswordViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11575D8B4F64C2E805372A5 /* AccountExportPasswordViewFactory.swift */; }; 623474C49445578F030291B0 /* ParaStkStakeSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0B2C32E11E2F7F3D4A1D3AB /* ParaStkStakeSetupWireframe.swift */; }; + 62B2298F132DB0CE0794DD7A /* ReferendumFullDescriptionWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E6825E525785A1A12C62E7 /* ReferendumFullDescriptionWireframe.swift */; }; 63185C6D67EAEB2867069AB9 /* ParitySignerWelcomeProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CBB8745F8C36BB107625E8F /* ParitySignerWelcomeProtocols.swift */; }; 640A79BD1335394818E70366 /* WalletHistoryFilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6884DFC1AA1B995C21C274C /* WalletHistoryFilterViewController.swift */; }; 641D7CF89F37B1890516015E /* ParitySignerTxScanProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F10F130391C4B3652FE8F59 /* ParitySignerTxScanProtocols.swift */; }; @@ -2271,6 +2274,9 @@ 882C29AA28DC7B3D009CA4B6 /* SubstrateStorageMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882C29A928DC7B3D009CA4B6 /* SubstrateStorageMigrator.swift */; }; 882C29AC28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882C29AB28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift */; }; 882C29AE28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882C29AD28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift */; }; + 88300944291409600030B31C /* Markdown in Frameworks */ = {isa = PBXBuildFile; productRef = 88300943291409600030B31C /* Markdown */; }; + 8830094629140CC00030B31C /* test.md in Resources */ = {isa = PBXBuildFile; fileRef = 8830094529140CBF0030B31C /* test.md */; }; + 88300948291410FC0030B31C /* Markdownosaur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88300947291410FC0030B31C /* Markdownosaur.swift */; }; 8831F10028C65B95009F7682 /* AssetLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8831F0FF28C65B95009F7682 /* AssetLock.swift */; }; 8836AF4428AA293500A94EDD /* CurrencyManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8836AF4328AA293500A94EDD /* CurrencyManagerTests.swift */; }; 8836AF4828AA49AB00A94EDD /* Currency+btc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8836AF4728AA49AB00A94EDD /* Currency+btc.swift */; }; @@ -2379,6 +2385,7 @@ 90A3F46EF181DC2B821CC80C /* CrowdloanContributionConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F791FE1B479CE1DF936F79F /* CrowdloanContributionConfirmViewFactory.swift */; }; 90ACE8690DA095E4F45494E9 /* TransferConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F7865BACFB8591F67D8EE06 /* TransferConfirmProtocols.swift */; }; 90EFE3768F1375470FDBE6F6 /* PurchaseViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AA3BF0C9C1E0E2C67D962F5 /* PurchaseViewFactory.swift */; }; + 91201789084DD9A419CA8CD3 /* ReferendumFullDescriptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F080BC55D9575EBE4216283C /* ReferendumFullDescriptionViewController.swift */; }; 912ECC319A48CAD09FB694AC /* AssetsSearchProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F9F9E43E296386A7F138326 /* AssetsSearchProtocols.swift */; }; 91530F7301CA39654E008580 /* DAppBrowserInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A4DFCC4236D25A3D59F809 /* DAppBrowserInteractor.swift */; }; 91A1286763617DE022BD495F /* LedgerInstructionsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B08ACC71BE679A48A7B66E /* LedgerInstructionsPresenter.swift */; }; @@ -2420,6 +2427,7 @@ 9E4E458C92D12B24D5EAD893 /* ControllerAccountInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 748E0AF1A286016CB220155C /* ControllerAccountInteractor.swift */; }; 9F3E2D64D77BF89B474BF1E3 /* DAppOperationConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FBC2EA83A121CEBD25549D /* DAppOperationConfirmViewController.swift */; }; 9F4A48B1BE3A1110A0CF9F36 /* ReferralCrowdloanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DDDB2B35CD3299F50613141 /* ReferralCrowdloanViewController.swift */; }; + A05C2B3458F12EFE1633D917 /* ReferendumFullDescriptionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAEF44ADECD66B49E3430365 /* ReferendumFullDescriptionPresenter.swift */; }; A07A987DE3047AF1A786D511 /* DAppListViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11BB49F165F64A7EF6418EB4 /* DAppListViewLayout.swift */; }; A090FF206B56A0E465C62072 /* CrowdloanListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86F7A369E31DCB9ABD556EE9 /* CrowdloanListPresenter.swift */; }; A14308E2633921838166C843 /* ParaStkUnstakeConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F2450A063F4D66EFDF6B8A /* ParaStkUnstakeConfirmViewFactory.swift */; }; @@ -2464,6 +2472,7 @@ AE528E4D26852C380058935A /* ValidatorSearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE528E4C26852C380058935A /* ValidatorSearchViewModel.swift */; }; AE528E4F26852E410058935A /* ValidatorSearchViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE528E4E26852E410058935A /* ValidatorSearchViewModelFactory.swift */; }; AE5A205F26A5A54800925400 /* ExtrinsicOperationFactoryStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5A205E26A5A54800925400 /* ExtrinsicOperationFactoryStub.swift */; }; + AE6C737BD94BCD88A06287E2 /* ReferendumFullDescriptionProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 722DC609FE13ACBEE4328873 /* ReferendumFullDescriptionProtocols.swift */; }; AE6DE7322627EA930018D5B5 /* PayoutCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6DE7312627EA930018D5B5 /* PayoutCall.swift */; }; AE6F7FDF2685E812002BBC3E /* ValidatorListFilterPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6F7FD82685E812002BBC3E /* ValidatorListFilterPresenter.swift */; }; AE6F7FE02685E812002BBC3E /* ValidatorListFilterProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6F7FD92685E812002BBC3E /* ValidatorListFilterProtocols.swift */; }; @@ -2904,6 +2913,7 @@ F85E4E18D7D535538D52B950 /* ParaStkSelectCollatorsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE545FC135A5D1C49CE3770 /* ParaStkSelectCollatorsViewLayout.swift */; }; F85F1BCAD47F0596FBFBA110 /* ParaStkRebondWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C2B583DB30C6C818B0F952D /* ParaStkRebondWireframe.swift */; }; F88D85C73094F6A1FC494D87 /* DAppSearchWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A191B92AD171FDDDD8C30E2 /* DAppSearchWireframe.swift */; }; + F8C0CA3DDBCB5E509295F099 /* ReferendumFullDescriptionViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAF9ED27CF12B7DA8B1378CF /* ReferendumFullDescriptionViewFactory.swift */; }; FA62AACACA15CB04275DE957 /* ParaStkYourCollatorsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A2FD02269432066884F5AF /* ParaStkYourCollatorsInteractor.swift */; }; FA894DFA8EEBB0B4562CD788 /* LedgerAccountConfirmationViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392B5AA43C68E640C9FDEE04 /* LedgerAccountConfirmationViewFactory.swift */; }; FB405A41F9B89097016D4C78 /* ChainAddressDetailsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 245DED717B5B3FC380C24E3D /* ChainAddressDetailsWireframe.swift */; }; @@ -3168,6 +3178,7 @@ 578743E9101B334BFBE44CB6 /* ParaStkRedeemWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemWireframe.swift; sourceTree = ""; }; 57C624E71FCE0FFF8EAD5BA9 /* RecommendedValidatorListWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RecommendedValidatorListWireframe.swift; sourceTree = ""; }; 57CDCB8CF3D8EBE5DA7A5A30 /* ReferendumFullDetailsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsViewLayout.swift; sourceTree = ""; }; + 57E6825E525785A1A12C62E7 /* ReferendumFullDescriptionWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDescriptionWireframe.swift; sourceTree = ""; }; 58612684146AD03AD7BC30DF /* ChangeWatchOnlyViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChangeWatchOnlyViewLayout.swift; sourceTree = ""; }; 594BC61689EC942ED0A64A4A /* ReferralCrowdloanViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferralCrowdloanViewLayout.swift; sourceTree = ""; }; 597A3C3F2937333D0EC7ABD5 /* AdvancedWalletViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AdvancedWalletViewController.swift; sourceTree = ""; }; @@ -3219,6 +3230,7 @@ 70A399F229B59A854FEA6D91 /* LedgerPerformOperationViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerPerformOperationViewLayout.swift; sourceTree = ""; }; 71285CF636B32ACD8EB5519E /* ReferralCrowdloanViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferralCrowdloanViewFactory.swift; sourceTree = ""; }; 715F4A252715B543F11087AB /* DAppOperationConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmInteractor.swift; sourceTree = ""; }; + 722DC609FE13ACBEE4328873 /* ReferendumFullDescriptionProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDescriptionProtocols.swift; sourceTree = ""; }; 72FEB9C65F32B7A4FD27C9EB /* ParitySignerTxScanInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerTxScanInteractor.swift; sourceTree = ""; }; 7306D50F278F6CC90DC88F27 /* AccountConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountConfirmPresenter.swift; sourceTree = ""; }; 7320E1CD9EA1A33EA29D0700 /* AnalyticsValidatorsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsValidatorsPresenter.swift; sourceTree = ""; }; @@ -5226,6 +5238,8 @@ 882C29A928DC7B3D009CA4B6 /* SubstrateStorageMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubstrateStorageMigrator.swift; sourceTree = ""; }; 882C29AB28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubstrateStorageVersion.swift; sourceTree = ""; }; 882C29AD28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StorageMigrating+CheckVersion.swift"; sourceTree = ""; }; + 8830094529140CBF0030B31C /* test.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = test.md; sourceTree = ""; }; + 88300947291410FC0030B31C /* Markdownosaur.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Markdownosaur.swift; sourceTree = ""; }; 8831F0FF28C65B95009F7682 /* AssetLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetLock.swift; sourceTree = ""; }; 8836AF4328AA293500A94EDD /* CurrencyManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyManagerTests.swift; sourceTree = ""; }; 8836AF4728AA49AB00A94EDD /* Currency+btc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Currency+btc.swift"; sourceTree = ""; }; @@ -5545,6 +5559,7 @@ B8B0A8174A9FFB8422A70D83 /* ParitySignerWelcomeWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerWelcomeWireframe.swift; sourceTree = ""; }; B90CEC70F101AA25A4C00021 /* YourValidatorListViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourValidatorListViewController.swift; sourceTree = ""; }; BAB2478DE3AF0885A3ED7ED8 /* StakingRedeemPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRedeemPresenter.swift; sourceTree = ""; }; + BAF9ED27CF12B7DA8B1378CF /* ReferendumFullDescriptionViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDescriptionViewFactory.swift; sourceTree = ""; }; BB5E8FAB4C12D7BFEEF576AD /* AnalyticsRewardDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsRewardDetailsWireframe.swift; sourceTree = ""; }; BC15D0B7B9F29E97FCECC1D2 /* AssetsManageViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetsManageViewLayout.swift; sourceTree = ""; }; BC216C4DBF86A9F3ADB3AECF /* ParitySignerAddConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddConfirmWireframe.swift; sourceTree = ""; }; @@ -5569,6 +5584,7 @@ C9978451AB2F4958E6FF117D /* YourWalletsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourWalletsViewFactory.swift; sourceTree = ""; }; C9990DF2F0214CD51E5388CE /* ReferendumVotersPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVotersPresenter.swift; sourceTree = ""; }; CAB80E4CA0D5FA56612318A2 /* ChangeWatchOnlyProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChangeWatchOnlyProtocols.swift; sourceTree = ""; }; + CAEF44ADECD66B49E3430365 /* ReferendumFullDescriptionPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDescriptionPresenter.swift; sourceTree = ""; }; CB441F15E16B07196DD9CE9D /* ParaStkUnstakeProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeProtocols.swift; sourceTree = ""; }; CB9150FEC66FC503CF1BD1D0 /* WalletHistoryFilterPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletHistoryFilterPresenter.swift; sourceTree = ""; }; CC17D12DCD0CDAF0BC13D80D /* StakingUnbondSetupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondSetupViewController.swift; sourceTree = ""; }; @@ -5583,6 +5599,7 @@ CF891BE39D442C2D06DDF3BB /* StakingRewardDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardDetailsProtocols.swift; sourceTree = ""; }; CFA54AB88E24A2053F289D74 /* GovernanceUnlockSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupInteractor.swift; sourceTree = ""; }; D02E38ABE379CA48E63328C4 /* DAppBrowserProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppBrowserProtocols.swift; sourceTree = ""; }; + D087F5710630FCC968B65FB5 /* ReferendumFullDescriptionViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDescriptionViewLayout.swift; sourceTree = ""; }; D0D4E719EB5AC6CDB97BAB5C /* ParaStkUnstakeWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeWireframe.swift; sourceTree = ""; }; D101339CC1292531CC4DB0AC /* StakingUnbondSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondSetupInteractor.swift; sourceTree = ""; }; D1852EB0DD9E0C39E0AAEE68 /* AssetListPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetListPresenter.swift; sourceTree = ""; }; @@ -5633,6 +5650,7 @@ E1E60EF37AC0A7646ED8FE64 /* AccountImportViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountImportViewFactory.swift; sourceTree = ""; }; E20124142C4011901EF55AAA /* ParitySignerAddressesViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddressesViewLayout.swift; sourceTree = ""; }; E29DAC8F2DB0F7BF909812FA /* DAppTxDetailsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsViewLayout.swift; sourceTree = ""; }; + E2E47548C4A216327B05A63C /* ReferendumFullDescriptionInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDescriptionInteractor.swift; sourceTree = ""; }; E2F3E725280823CF00CF31B5 /* ETHAccountInjection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ETHAccountInjection.swift; sourceTree = ""; }; E30E541992BF608923DABE5F /* LocksWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LocksWireframe.swift; sourceTree = ""; }; E4C77FD258A19F08F3955AC4 /* ParaStkUnstakeConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeConfirmInteractor.swift; sourceTree = ""; }; @@ -5668,6 +5686,7 @@ EFB278373745C20822442686 /* ExportSeedPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ExportSeedPresenter.swift; sourceTree = ""; }; F02DBCA4A63A5E52E3739374 /* ControllerAccountConfirmationViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ControllerAccountConfirmationViewFactory.swift; sourceTree = ""; }; F0548D67378CB1EFEC2D5784 /* Pods-novawalletAll-novawalletIntegrationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-novawalletAll-novawalletIntegrationTests.release.xcconfig"; path = "Target Support Files/Pods-novawalletAll-novawalletIntegrationTests/Pods-novawalletAll-novawalletIntegrationTests.release.xcconfig"; sourceTree = ""; }; + F080BC55D9575EBE4216283C /* ReferendumFullDescriptionViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDescriptionViewController.swift; sourceTree = ""; }; F1A9B9D741BABBCE6C70BE45 /* LedgerDiscoverProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerDiscoverProtocols.swift; sourceTree = ""; }; F23E38DCBC74C528D7839B76 /* CrowdloanContributionSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupInteractor.swift; sourceTree = ""; }; F23EDFB699CAEEADC9263A0D /* DAppAuthSettingsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthSettingsViewFactory.swift; sourceTree = ""; }; @@ -5880,6 +5899,7 @@ buildActionMask = 2147483647; files = ( 352B75BEB10A48CC6CE64D4A /* Pods_novawalletAll_novawallet.framework in Frameworks */, + 88300944291409600030B31C /* Markdown in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -8748,6 +8768,7 @@ B320B465EE16F566DDFE5D8C /* ReferendumVoteConfirm */, 847157792910F06000D7D003 /* GovernanceUnlock */, FD4B0C614F7A70D8FB51A1C3 /* GovernanceUnlockSetup */, + ABAF6F503B172CEE34E19030 /* ReferendumFullDescription */, ); path = Governance; sourceTree = ""; @@ -12688,6 +12709,22 @@ path = Instructions; sourceTree = ""; }; + ABAF6F503B172CEE34E19030 /* ReferendumFullDescription */ = { + isa = PBXGroup; + children = ( + 8830094529140CBF0030B31C /* test.md */, + 88300947291410FC0030B31C /* Markdownosaur.swift */, + 722DC609FE13ACBEE4328873 /* ReferendumFullDescriptionProtocols.swift */, + 57E6825E525785A1A12C62E7 /* ReferendumFullDescriptionWireframe.swift */, + CAEF44ADECD66B49E3430365 /* ReferendumFullDescriptionPresenter.swift */, + E2E47548C4A216327B05A63C /* ReferendumFullDescriptionInteractor.swift */, + F080BC55D9575EBE4216283C /* ReferendumFullDescriptionViewController.swift */, + D087F5710630FCC968B65FB5 /* ReferendumFullDescriptionViewLayout.swift */, + BAF9ED27CF12B7DA8B1378CF /* ReferendumFullDescriptionViewFactory.swift */, + ); + path = ReferendumFullDescription; + sourceTree = ""; + }; ADEC075C60AA6D00785D2BDF /* AssetList */ = { isa = PBXGroup; children = ( @@ -14047,6 +14084,9 @@ dependencies = ( ); name = novawallet; + packageProductDependencies = ( + 88300943291409600030B31C /* Markdown */, + ); productName = fearless; productReference = 849013A824A80984008F705E /* novawallet.app */; productType = "com.apple.product-type.application"; @@ -14106,6 +14146,9 @@ ru, ); mainGroup = 8490139F24A80984008F705E; + packageReferences = ( + 88300942291409600030B31C /* XCRemoteSwiftPackageReference "swift-markdown" */, + ); productRefGroup = 849013A924A80984008F705E /* Products */; projectDirPath = ""; projectRoot = ""; @@ -14129,6 +14172,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8830094629140CC00030B31C /* test.md in Resources */, 848E6BE1276328B500C91022 /* PublicSans-Medium.otf in Resources */, 84C1B98D24F55EB200FE5470 /* AccountTableViewCell.xib in Resources */, 849013FC24A92A05008F705E /* novawallet.release.xcconfig in Resources */, @@ -15944,6 +15988,7 @@ 8428228A289B1E5C00163031 /* TableHeaderLayoutUpdatable.swift in Sources */, 84EE2FAF2891215200A98816 /* WalletManageTableViewCell.swift in Sources */, 849B563527A70DDE007D5528 /* ExtrinsicProcessor+Matching.swift in Sources */, + 88300948291410FC0030B31C /* Markdownosaur.swift in Sources */, 94B0F0C84AF74B3CD7223C3A /* AccountConfirmPresenter.swift in Sources */, 8468B87224F63D3A00B76BC6 /* AddAccount+AccountCreateWireframe.swift in Sources */, 9DFB37659A6B911A4D54623E /* AccountConfirmInteractor.swift in Sources */, @@ -17139,6 +17184,13 @@ 16098DABB1C9C058C1965F1D /* GovernanceUnlockSetupViewController.swift in Sources */, 0E71EA5AE04940824AEA01C7 /* GovernanceUnlockSetupViewLayout.swift in Sources */, E28F3762EAC9A4E5D21342D4 /* GovernanceUnlockSetupViewFactory.swift in Sources */, + AE6C737BD94BCD88A06287E2 /* ReferendumFullDescriptionProtocols.swift in Sources */, + 62B2298F132DB0CE0794DD7A /* ReferendumFullDescriptionWireframe.swift in Sources */, + A05C2B3458F12EFE1633D917 /* ReferendumFullDescriptionPresenter.swift in Sources */, + 1752940C07D7BA41801E3853 /* ReferendumFullDescriptionInteractor.swift in Sources */, + 91201789084DD9A419CA8CD3 /* ReferendumFullDescriptionViewController.swift in Sources */, + 3A4743C7C74BE4F74F6390F6 /* ReferendumFullDescriptionViewLayout.swift in Sources */, + F8C0CA3DDBCB5E509295F099 /* ReferendumFullDescriptionViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -17940,6 +17992,25 @@ }; /* End XCConfigurationList section */ +/* Begin XCRemoteSwiftPackageReference section */ + 88300942291409600030B31C /* XCRemoteSwiftPackageReference "swift-markdown" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-markdown.git"; + requirement = { + branch = main; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 88300943291409600030B31C /* Markdown */ = { + isa = XCSwiftPackageProductDependency; + package = 88300942291409600030B31C /* XCRemoteSwiftPackageReference "swift-markdown" */; + productName = Markdown; + }; +/* End XCSwiftPackageProductDependency section */ + /* Begin XCVersionGroup section */ 843910CA253F7E6500E3C217 /* SubstrateDataModel.xcdatamodeld */ = { isa = XCVersionGroup; diff --git a/novawallet.xcworkspace/xcshareddata/swiftpm/Package.resolved b/novawallet.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000000..b854da4a43 --- /dev/null +++ b/novawallet.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,23 @@ +{ + "pins" : [ + { + "identity" : "swift-cmark", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-cmark.git", + "state" : { + "branch" : "gfm", + "revision" : "bfdc057b5a02fc65af20771a7ba08f9c944eb117" + } + }, + { + "identity" : "swift-markdown", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-markdown.git", + "state" : { + "branch" : "main", + "revision" : "d491147940587dbadfb3472354f4d0c6e063e061" + } + } + ], + "version" : 2 +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 378ae43a10..4aeef1de81 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -341,7 +341,9 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { func opeDApp(at _: Int) {} - func readFullDescription() {} + func readFullDescription() { + wireframe.showFullDescription(from: view, referendum: referendum) + } func openFullDetails() { guard let actionDetails = actionDetails else { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 818ca0e8c4..b62404b693 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -59,4 +59,6 @@ protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, referendum: ReferendumLocal, type: ReferendumVotersType ) + + func showFullDescription(from: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index 7888f06489..8c55748e76 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -60,4 +60,18 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { view?.controller.present(navigationController, animated: true) } + + func showFullDescription(from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal) { + guard + let fullDescriptionView = ReferendumFullDescriptionViewFactory.createView( + state: state, + referendum: referendum + ) else { + return + } + + let navigationController = FearlessNavigationController(rootViewController: fullDescriptionView.controller) + + view?.controller.present(navigationController, animated: true) + } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index 2a76055c46..eaaa9e2ea6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -47,8 +47,6 @@ final class ReferendumDetailsTitleView: UIView { $0.textContainer.lineFragmentPadding = 0 } - private var readMoreContainer: UIView? - let moreButton: RoundedButton = .create { button in button.applyIconStyle() @@ -74,40 +72,21 @@ final class ReferendumDetailsTitleView: UIView { } private func setupLayout() { - let buttonContainer = UIView.hStack([ - moreButton, - UIView() - ]) - - readMoreContainer = buttonContainer - let content = UIView.vStack( + alignment: .leading, + spacing: 8, [ - UIView.hStack( - [ - accountContainerView, - UIView() - ] - ), - UIView.vStack( - spacing: 6, - [ - titleLabel, - textView, - buttonContainer - ] - ) + accountContainerView, + titleLabel, + textView, + moreButton ] ) - + content.setCustomSpacing(0, after: accountContainerView) addSubview(content) content.snp.makeConstraints { $0.edges.equalToSuperview() } - - moreButton.snp.makeConstraints { make in - make.height.equalTo(32) - } } } @@ -153,11 +132,11 @@ extension ReferendumDetailsTitleView { preferredLanguages: locale.rLanguages ) - readMoreContainer?.isHidden = !details.shouldReadMore + moreButton.isHidden = !details.shouldReadMore } else { titleLabel.isHidden = true textView.isHidden = true - readMoreContainer?.isHidden = true + moreButton.isHidden = true } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift new file mode 100644 index 0000000000..0b3562b96d --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift @@ -0,0 +1,413 @@ +import UIKit +import Markdown + +// swiftlint:disable line_length +// swiftlint:disable force_cast +public struct Markdownosaur: MarkupVisitor { + let baseFontSize: CGFloat = 15.0 + let baseTextColor: UIColor = R.color.colorWhite64()! + + public init() {} + + public mutating func attributedString(from document: Document) -> NSAttributedString { + visit(document) + } + + public mutating func defaultVisit(_ markup: Markup) -> NSAttributedString { + let result = NSMutableAttributedString() + + for child in markup.children { + result.append(visit(child)) + } + + return result + } + + public mutating func visitText(_ text: Text) -> NSAttributedString { + NSAttributedString(string: text.plainText, attributes: [ + .font: UIFont.systemFont(ofSize: baseFontSize, weight: .regular), + .foregroundColor: baseTextColor + ]) + } + + public mutating func visitEmphasis(_ emphasis: Emphasis) -> NSAttributedString { + let result = NSMutableAttributedString() + + for child in emphasis.children { + result.append(visit(child)) + } + + result.applyEmphasis() + + return result + } + + public mutating func visitStrong(_ strong: Strong) -> NSAttributedString { + let result = NSMutableAttributedString() + + for child in strong.children { + result.append(visit(child)) + } + + result.applyStrong() + + return result + } + + public mutating func visitParagraph(_ paragraph: Paragraph) -> NSAttributedString { + let result = NSMutableAttributedString() + + for child in paragraph.children { + result.append(visit(child)) + } + + if paragraph.hasSuccessor { + result.append(paragraph.isContainedInList ? .singleNewline(withFontSize: baseFontSize) : .doubleNewline(withFontSize: baseFontSize)) + } + + return result + } + + public mutating func visitHeading(_ heading: Heading) -> NSAttributedString { + let result = NSMutableAttributedString() + + for child in heading.children { + result.append(visit(child)) + } + + result.applyHeading(withLevel: heading.level) + + if heading.hasSuccessor { + result.append(.doubleNewline(withFontSize: baseFontSize)) + } + + return result + } + + public mutating func visitLink(_ link: Link) -> NSAttributedString { + let result = NSMutableAttributedString() + + for child in link.children { + result.append(visit(child)) + } + + let url = link.destination != nil ? URL(string: link.destination!) : nil + + result.applyLink(withURL: url) + + return result + } + + public mutating func visitInlineCode(_ inlineCode: InlineCode) -> NSAttributedString { + NSAttributedString(string: inlineCode.code, attributes: [.font: UIFont.monospacedSystemFont(ofSize: baseFontSize - 1.0, weight: .regular), .foregroundColor: UIColor.systemGray]) + } + + public func visitCodeBlock(_ codeBlock: CodeBlock) -> NSAttributedString { + let result = NSMutableAttributedString(string: codeBlock.code, attributes: [.font: UIFont.monospacedSystemFont(ofSize: baseFontSize - 1.0, weight: .regular), .foregroundColor: UIColor.systemGray]) + + if codeBlock.hasSuccessor { + result.append(.singleNewline(withFontSize: baseFontSize)) + } + + return result + } + + public mutating func visitStrikethrough(_ strikethrough: Strikethrough) -> NSAttributedString { + let result = NSMutableAttributedString() + + for child in strikethrough.children { + result.append(visit(child)) + } + + result.applyStrikethrough() + + return result + } + + public mutating func visitUnorderedList(_ unorderedList: UnorderedList) -> NSAttributedString { + let result = NSMutableAttributedString() + + let font = UIFont.systemFont(ofSize: baseFontSize, weight: .regular) + + for listItem in unorderedList.listItems { + var listItemAttributes: [NSAttributedString.Key: Any] = [:] + + let listItemParagraphStyle = NSMutableParagraphStyle() + + let baseLeftMargin: CGFloat = 15.0 + let leftMarginOffset = baseLeftMargin + (20.0 * CGFloat(unorderedList.listDepth)) + let spacingFromIndex: CGFloat = 8.0 + let bulletWidth = ceil(NSAttributedString(string: "•", attributes: [.font: font]).size().width) + let firstTabLocation = leftMarginOffset + bulletWidth + let secondTabLocation = firstTabLocation + spacingFromIndex + + listItemParagraphStyle.tabStops = [ + NSTextTab(textAlignment: .right, location: firstTabLocation), + NSTextTab(textAlignment: .left, location: secondTabLocation) + ] + + listItemParagraphStyle.headIndent = secondTabLocation + + listItemAttributes[.paragraphStyle] = listItemParagraphStyle + listItemAttributes[.font] = UIFont.systemFont(ofSize: baseFontSize, weight: .regular) + listItemAttributes[.listDepth] = unorderedList.listDepth + + let listItemAttributedString = visit(listItem).mutableCopy() as! NSMutableAttributedString + listItemAttributedString.insert(NSAttributedString(string: "\t•\t", attributes: listItemAttributes), at: 0) + + result.append(listItemAttributedString) + } + + if unorderedList.hasSuccessor { + result.append(.doubleNewline(withFontSize: baseFontSize)) + } + + return result + } + + public mutating func visitListItem(_ listItem: ListItem) -> NSAttributedString { + let result = NSMutableAttributedString() + + for child in listItem.children { + result.append(visit(child)) + } + + if listItem.hasSuccessor { + result.append(.singleNewline(withFontSize: baseFontSize)) + } + + return result + } + + public mutating func visitOrderedList(_ orderedList: OrderedList) -> NSAttributedString { + let result = NSMutableAttributedString() + + for (index, listItem) in orderedList.listItems.enumerated() { + var listItemAttributes: [NSAttributedString.Key: Any] = [:] + + let font = UIFont.systemFont(ofSize: baseFontSize, weight: .regular) + let numeralFont = UIFont.monospacedDigitSystemFont(ofSize: baseFontSize, weight: .regular) + + let listItemParagraphStyle = NSMutableParagraphStyle() + + // Implement a base amount to be spaced from the left side at all times to better visually differentiate it as a list + let baseLeftMargin: CGFloat = 15.0 + let leftMarginOffset = baseLeftMargin + (20.0 * CGFloat(orderedList.listDepth)) + + // Grab the highest number to be displayed and measure its width (yes normally some digits are wider than others but since we're using the numeral mono font all will be the same width in this case) + let highestNumberInList = orderedList.childCount + let numeralColumnWidth = ceil(NSAttributedString(string: "\(highestNumberInList).", attributes: [.font: numeralFont]).size().width) + + let spacingFromIndex: CGFloat = 8.0 + let firstTabLocation = leftMarginOffset + numeralColumnWidth + let secondTabLocation = firstTabLocation + spacingFromIndex + + listItemParagraphStyle.tabStops = [ + NSTextTab(textAlignment: .right, location: firstTabLocation), + NSTextTab(textAlignment: .left, location: secondTabLocation) + ] + + listItemParagraphStyle.headIndent = secondTabLocation + + listItemAttributes[.paragraphStyle] = listItemParagraphStyle + listItemAttributes[.font] = font + listItemAttributes[.listDepth] = orderedList.listDepth + + let listItemAttributedString = visit(listItem).mutableCopy() as! NSMutableAttributedString + + // Same as the normal list attributes, but for prettiness in formatting we want to use the cool monospaced numeral font + var numberAttributes = listItemAttributes + numberAttributes[.font] = numeralFont + + let numberAttributedString = NSAttributedString(string: "\t\(index + 1).\t", attributes: numberAttributes) + listItemAttributedString.insert(numberAttributedString, at: 0) + + result.append(listItemAttributedString) + } + + if orderedList.hasSuccessor { + result.append(orderedList.isContainedInList ? .singleNewline(withFontSize: baseFontSize) : .doubleNewline(withFontSize: baseFontSize)) + } + + return result + } + + public mutating func visitBlockQuote(_ blockQuote: BlockQuote) -> NSAttributedString { + let result = NSMutableAttributedString() + + for child in blockQuote.children { + var quoteAttributes: [NSAttributedString.Key: Any] = [:] + + let quoteParagraphStyle = NSMutableParagraphStyle() + + let baseLeftMargin: CGFloat = 15.0 + let leftMarginOffset = baseLeftMargin + (20.0 * CGFloat(blockQuote.quoteDepth)) + + quoteParagraphStyle.tabStops = [NSTextTab(textAlignment: .left, location: leftMarginOffset)] + + quoteParagraphStyle.headIndent = leftMarginOffset + + quoteAttributes[.paragraphStyle] = quoteParagraphStyle + quoteAttributes[.font] = UIFont.systemFont(ofSize: baseFontSize, weight: .regular) + quoteAttributes[.listDepth] = blockQuote.quoteDepth + + let quoteAttributedString = visit(child).mutableCopy() as! NSMutableAttributedString + quoteAttributedString.insert(NSAttributedString(string: "\t", attributes: quoteAttributes), at: 0) + + quoteAttributedString.addAttribute(.foregroundColor, value: UIColor.systemGray) + + result.append(quoteAttributedString) + } + + if blockQuote.hasSuccessor { + result.append(.doubleNewline(withFontSize: baseFontSize)) + } + + return result + } +} + +// MARK: - Extensions Land + +extension NSMutableAttributedString { + func applyEmphasis() { + enumerateAttribute(.font, in: NSRange(location: 0, length: length), options: []) { value, range, _ in + guard let font = value as? UIFont else { return } + + let newFont = font.apply(newTraits: .traitItalic) + addAttribute(.font, value: newFont, range: range) + } + } + + func applyStrong() { + enumerateAttribute(.font, in: NSRange(location: 0, length: length), options: []) { value, range, _ in + guard let font = value as? UIFont else { return } + + let newFont = font.apply(newTraits: .traitBold) + addAttribute(.font, value: newFont, range: range) + } + } + + func applyLink(withURL url: URL?) { + addAttribute(.foregroundColor, value: UIColor.systemBlue) + + if let url = url { + addAttribute(.link, value: url) + } + } + + func applyBlockquote() { + addAttribute(.foregroundColor, value: UIColor.systemGray) + } + + func applyHeading(withLevel headingLevel: Int) { + enumerateAttribute(.font, in: NSRange(location: 0, length: length), options: []) { value, range, _ in + guard let font = value as? UIFont else { return } + + let newFont = font.apply(newTraits: .traitBold, newPointSize: 28.0 - CGFloat(headingLevel * 2)) + addAttribute(.font, value: newFont, range: range) + } + } + + func applyStrikethrough() { + addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue) + } +} + +extension UIFont { + func apply(newTraits: UIFontDescriptor.SymbolicTraits, newPointSize: CGFloat? = nil) -> UIFont { + var existingTraits = fontDescriptor.symbolicTraits + existingTraits.insert(newTraits) + + guard let newFontDescriptor = fontDescriptor.withSymbolicTraits(existingTraits) else { return self } + return UIFont(descriptor: newFontDescriptor, size: newPointSize ?? pointSize) + } +} + +extension ListItemContainer { + /// Depth of the list if nested within others. Index starts at 0. + var listDepth: Int { + var index = 0 + + var currentElement = parent + + while currentElement != nil { + if currentElement is ListItemContainer { + index += 1 + } + + currentElement = currentElement?.parent + } + + return index + } +} + +extension BlockQuote { + /// Depth of the quote if nested within others. Index starts at 0. + var quoteDepth: Int { + var index = 0 + + var currentElement = parent + + while currentElement != nil { + if currentElement is BlockQuote { + index += 1 + } + + currentElement = currentElement?.parent + } + + return index + } +} + +extension NSAttributedString.Key { + static let listDepth = NSAttributedString.Key("ListDepth") + static let quoteDepth = NSAttributedString.Key("QuoteDepth") +} + +extension NSMutableAttributedString { + func addAttribute(_ name: NSAttributedString.Key, value: Any) { + addAttribute(name, value: value, range: NSRange(location: 0, length: length)) + } + + func addAttributes(_ attrs: [NSAttributedString.Key: Any]) { + addAttributes(attrs, range: NSRange(location: 0, length: length)) + } +} + +extension Markup { + /// Returns true if this element has sibling elements after it. + var hasSuccessor: Bool { + guard let childCount = parent?.childCount else { return false } + return indexInParent < childCount - 1 + } + + var isContainedInList: Bool { + var currentElement = parent + + while currentElement != nil { + if currentElement is ListItemContainer { + return true + } + + currentElement = currentElement?.parent + } + + return false + } +} + +extension NSAttributedString { + static func singleNewline(withFontSize fontSize: CGFloat) -> NSAttributedString { + NSAttributedString(string: "\n", attributes: [.font: UIFont.systemFont(ofSize: fontSize, weight: .regular)]) + } + + static func doubleNewline(withFontSize fontSize: CGFloat) -> NSAttributedString { + NSAttributedString(string: "\n\n", attributes: [.font: UIFont.systemFont(ofSize: fontSize, weight: .regular)]) + } +} + +// swiftlint:enable line_length +// swiftlint:enable force_cast diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionInteractor.swift new file mode 100644 index 0000000000..01bd422a9d --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionInteractor.swift @@ -0,0 +1,7 @@ +import UIKit + +final class ReferendumFullDescriptionInteractor { + weak var presenter: ReferendumFullDescriptionInteractorOutputProtocol! +} + +extension ReferendumFullDescriptionInteractor: ReferendumFullDescriptionInteractorInputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift new file mode 100644 index 0000000000..b76af26969 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift @@ -0,0 +1,21 @@ +import Foundation + +final class ReferendumFullDescriptionPresenter { + weak var view: ReferendumFullDescriptionViewProtocol? + let wireframe: ReferendumFullDescriptionWireframeProtocol + let interactor: ReferendumFullDescriptionInteractorInputProtocol + + init( + interactor: ReferendumFullDescriptionInteractorInputProtocol, + wireframe: ReferendumFullDescriptionWireframeProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + } +} + +extension ReferendumFullDescriptionPresenter: ReferendumFullDescriptionPresenterProtocol { + func setup() {} +} + +extension ReferendumFullDescriptionPresenter: ReferendumFullDescriptionInteractorOutputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift new file mode 100644 index 0000000000..9dfa0a2ff1 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift @@ -0,0 +1,11 @@ +protocol ReferendumFullDescriptionViewProtocol: ControllerBackedProtocol {} + +protocol ReferendumFullDescriptionPresenterProtocol: AnyObject { + func setup() +} + +protocol ReferendumFullDescriptionInteractorInputProtocol: AnyObject {} + +protocol ReferendumFullDescriptionInteractorOutputProtocol: AnyObject {} + +protocol ReferendumFullDescriptionWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift new file mode 100644 index 0000000000..e2715a0b88 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift @@ -0,0 +1,49 @@ +import UIKit + +final class ReferendumFullDescriptionViewController: UIViewController, ViewHolder { + typealias RootViewType = ReferendumFullDescriptionViewLayout + + let presenter: ReferendumFullDescriptionPresenterProtocol + + init(presenter: ReferendumFullDescriptionPresenterProtocol) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = ReferendumFullDescriptionViewLayout() + } + + // swiftlint:disable line_length + override func viewDidLoad() { + super.viewDidLoad() + + presenter.setup() + + guard let markdownText = try? createMarkdownTextSample() else { + return + } + didRecieve( + title: "Polkadot and Kusama participation in the 10th Pais Digital Chile Summit.", + description: markdownText + ) + } + + private func createMarkdownTextSample() throws -> String { + let url = Bundle.main.url(forResource: "test", withExtension: "md")! + let data = try Data(contentsOf: url) + return String(data: data, encoding: .utf8)! + } +} + +extension ReferendumFullDescriptionViewController: ReferendumFullDescriptionViewProtocol { + func didRecieve(title: String, description: String) { + rootView.set(title: title) + rootView.set(markdownText: description) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift new file mode 100644 index 0000000000..477a311fc0 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift @@ -0,0 +1,17 @@ +import Foundation + +struct ReferendumFullDescriptionViewFactory { + static func createView(state _: GovernanceSharedState, referendum _: ReferendumLocal) -> ReferendumFullDescriptionViewProtocol? { + let interactor = ReferendumFullDescriptionInteractor() + let wireframe = ReferendumFullDescriptionWireframe() + + let presenter = ReferendumFullDescriptionPresenter(interactor: interactor, wireframe: wireframe) + + let view = ReferendumFullDescriptionViewController(presenter: presenter) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift new file mode 100644 index 0000000000..2f51f14a58 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift @@ -0,0 +1,55 @@ +import UIKit +import Markdown + +final class ReferendumFullDescriptionViewLayout: UIView { + let containerView: ScrollableContainerView = { + let view = ScrollableContainerView(axis: .vertical, respectsSafeArea: true) + view.stackView.layoutMargins = UIEdgeInsets(top: 12, left: 16, bottom: 24, right: 16) + view.stackView.isLayoutMarginsRelativeArrangement = true + view.stackView.alignment = .fill + return view + }() + + let titleLabel: UILabel = .create { + $0.textColor = R.color.colorWhite() + $0.font = .boldTitle1 + $0.numberOfLines = 0 + } + + let descriptionTextView: UITextView = .create { + $0.backgroundColor = .clear + $0.textColor = R.color.colorWhite64() + $0.font = .regularSubheadline + $0.isScrollEnabled = false + $0.isEditable = false + $0.textContainerInset = .zero + $0.textContainer.lineFragmentPadding = 0 + } + + override init(frame: CGRect) { + super.init(frame: frame) + + addSubview(containerView) + containerView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + containerView.stackView.addArrangedSubview(titleLabel) + containerView.stackView.addArrangedSubview(descriptionTextView) + containerView.stackView.setCustomSpacing(16, after: titleLabel) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func set(markdownText: String) { + let document = Document(parsing: markdownText) + var markdownosaur = Markdownosaur() + descriptionTextView.attributedText = markdownosaur.attributedString(from: document) + } + + func set(title: String) { + titleLabel.text = title + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionWireframe.swift new file mode 100644 index 0000000000..4be86a54cc --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class ReferendumFullDescriptionWireframe: ReferendumFullDescriptionWireframeProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/test.md b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/test.md new file mode 100644 index 0000000000..0020528b2c --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/test.md @@ -0,0 +1,287 @@ +Opening paragraph, with an ordered list of autumn leaves I found + +1. A big leaf +1. Some small leaves: + 1. Red (nested) + 2. **Orange** + 3. Yellow +1. A medium sized leaf that ~~maybe~~ was pancake shaped + +Unordered list of fruits: + +- Blueberries +- Apples + - Macintosh + - Honey crisp + - Cortland +- Banana + +### Fancy Header Title + +Here's what someone said: + +> I think blockquotes are cool + +Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! + +And then they mentiond code around `NSAttributedString` that looked like this code block: + +```swift +func yeah() -> NSAttributedString { + // TODO: Write code +} +``` + +Tables are even supported but (but need more than `NSAttributedString` for support :p) + +Opening paragraph, with an ordered list of autumn leaves I found + +1. A big leaf +1. Some small leaves: + 1. Red (nested) + 2. **Orange** + 3. Yellow +1. A medium sized leaf that ~~maybe~~ was pancake shaped + +Unordered list of fruits: + +- Blueberries +- Apples + - Macintosh + - Honey crisp + - Cortland +- Banana + +### Fancy Header Title + +Here's what someone said: + +> I think blockquotes are cool + +Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! + +And then they mentiond code around `NSAttributedString` that looked like this code block: + +```swift +func yeah() -> NSAttributedString { + // TODO: Write code +} +``` + +Tables are even supported but (but need more than `NSAttributedString` for support :p) + +Opening paragraph, with an ordered list of autumn leaves I found + +1. A big leaf +1. Some small leaves: + 1. Red (nested) + 2. **Orange** + 3. Yellow +1. A medium sized leaf that ~~maybe~~ was pancake shaped + +Unordered list of fruits: + +- Blueberries +- Apples + - Macintosh + - Honey crisp + - Cortland +- Banana + +### Fancy Header Title + +Here's what someone said: + +> I think blockquotes are cool + +Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! + +And then they mentiond code around `NSAttributedString` that looked like this code block: + +```swift +func yeah() -> NSAttributedString { + // TODO: Write code +} +``` + +Tables are even supported but (but need more than `NSAttributedString` for support :p) + +Opening paragraph, with an ordered list of autumn leaves I found + +1. A big leaf +1. Some small leaves: + 1. Red (nested) + 2. **Orange** + 3. Yellow +1. A medium sized leaf that ~~maybe~~ was pancake shaped + +Unordered list of fruits: + +- Blueberries +- Apples + - Macintosh + - Honey crisp + - Cortland +- Banana + +### Fancy Header Title + +Here's what someone said: + +> I think blockquotes are cool + +Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! + +And then they mentiond code around `NSAttributedString` that looked like this code block: + +```swift +func yeah() -> NSAttributedString { + // TODO: Write code +} +``` + +Tables are even supported but (but need more than `NSAttributedString` for support :p) + +Opening paragraph, with an ordered list of autumn leaves I found + +1. A big leaf +1. Some small leaves: + 1. Red (nested) + 2. **Orange** + 3. Yellow +1. A medium sized leaf that ~~maybe~~ was pancake shaped + +Unordered list of fruits: + +- Blueberries +- Apples + - Macintosh + - Honey crisp + - Cortland +- Banana + +### Fancy Header Title + +Here's what someone said: + +> I think blockquotes are cool + +Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! + +And then they mentiond code around `NSAttributedString` that looked like this code block: + +```swift +func yeah() -> NSAttributedString { + // TODO: Write code +} +``` + +Tables are even supported but (but need more than `NSAttributedString` for support :p) + +Opening paragraph, with an ordered list of autumn leaves I found + +1. A big leaf +1. Some small leaves: + 1. Red (nested) + 2. **Orange** + 3. Yellow +1. A medium sized leaf that ~~maybe~~ was pancake shaped + +Unordered list of fruits: + +- Blueberries +- Apples + - Macintosh + - Honey crisp + - Cortland +- Banana + +### Fancy Header Title + +Here's what someone said: + +> I think blockquotes are cool + +Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! + +And then they mentiond code around `NSAttributedString` that looked like this code block: + +```swift +func yeah() -> NSAttributedString { + // TODO: Write code +} +``` + +Tables are even supported but (but need more than `NSAttributedString` for support :p) + +Opening paragraph, with an ordered list of autumn leaves I found + +1. A big leaf +1. Some small leaves: + 1. Red (nested) + 2. **Orange** + 3. Yellow +1. A medium sized leaf that ~~maybe~~ was pancake shaped + +Unordered list of fruits: + +- Blueberries +- Apples + - Macintosh + - Honey crisp + - Cortland +- Banana + +### Fancy Header Title + +Here's what someone said: + +> I think blockquotes are cool + +Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! + +And then they mentiond code around `NSAttributedString` that looked like this code block: + +```swift +func yeah() -> NSAttributedString { + // TODO: Write code +} +``` + +Tables are even supported but (but need more than `NSAttributedString` for support :p) + +Opening paragraph, with an ordered list of autumn leaves I found + +1. A big leaf +1. Some small leaves: + 1. Red (nested) + 2. **Orange** + 3. Yellow +1. A medium sized leaf that ~~maybe~~ was pancake shaped + +Unordered list of fruits: + +- Blueberries +- Apples + - Macintosh + - Honey crisp + - Cortland +- Banana + +### Fancy Header Title + +Here's what someone said: + +> I think blockquotes are cool + +Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! + +And then they mentiond code around `NSAttributedString` that looked like this code block: + +```swift +func yeah() -> NSAttributedString { + // TODO: Write code +} +``` + +Tables are even supported but (but need more than `NSAttributedString` for support :p) From ba218ba3ba6c261416824bbb9b8f02bfd426563f Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 3 Nov 2022 23:18:53 +0500 Subject: [PATCH 151/229] add factory --- .../Operation/Gov1OperationFactory.swift | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift index c4554ce972..2b9358e7fa 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift @@ -1,9 +1,24 @@ -// -// Gov1OperationFactory.swift -// novawallet -// -// Created by Ruslan Rezin on 03.11.2022. -// Copyright © 2022 Nova Foundation. All rights reserved. -// - import Foundation +import RobinHood +import BigInt +import SubstrateSdk + +final class Gov1OperationFactory { + +} + +extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { + func fetchAllReferendumsWrapper(from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol) -> CompoundOperationWrapper<[ReferendumLocal]> { + <#code#> + } + + func fetchAccountVotesWrapper(for accountId: AccountId, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockHash: Data?) -> CompoundOperationWrapper { + <#code#> + } + + func fetchVotersWrapper(for referendumIndex: ReferendumIdLocal, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol) -> CompoundOperationWrapper<[ReferendumVoterLocal]> { + <#code#> + } + + +} From 6a33c84053560984450b0cc38bfdf59d8f0426b8 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 4 Nov 2022 10:56:14 +0300 Subject: [PATCH 152/229] added fonts and colors to markdown parser --- novawallet.xcodeproj/project.pbxproj | 4 - .../Markdownosaur.swift | 178 +++++++---- .../ReferendumFullDescriptionProtocols.swift | 4 +- ...erendumFullDescriptionViewController.swift | 17 +- .../ReferendumFullDescriptionViewLayout.swift | 2 +- .../ReferendumFullDescription/test.md | 287 ------------------ 6 files changed, 116 insertions(+), 376 deletions(-) delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/test.md diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 2deed008f6..14641d43a5 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2275,7 +2275,6 @@ 882C29AC28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882C29AB28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift */; }; 882C29AE28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882C29AD28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift */; }; 88300944291409600030B31C /* Markdown in Frameworks */ = {isa = PBXBuildFile; productRef = 88300943291409600030B31C /* Markdown */; }; - 8830094629140CC00030B31C /* test.md in Resources */ = {isa = PBXBuildFile; fileRef = 8830094529140CBF0030B31C /* test.md */; }; 88300948291410FC0030B31C /* Markdownosaur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88300947291410FC0030B31C /* Markdownosaur.swift */; }; 8831F10028C65B95009F7682 /* AssetLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8831F0FF28C65B95009F7682 /* AssetLock.swift */; }; 8836AF4428AA293500A94EDD /* CurrencyManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8836AF4328AA293500A94EDD /* CurrencyManagerTests.swift */; }; @@ -5238,7 +5237,6 @@ 882C29A928DC7B3D009CA4B6 /* SubstrateStorageMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubstrateStorageMigrator.swift; sourceTree = ""; }; 882C29AB28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubstrateStorageVersion.swift; sourceTree = ""; }; 882C29AD28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StorageMigrating+CheckVersion.swift"; sourceTree = ""; }; - 8830094529140CBF0030B31C /* test.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = test.md; sourceTree = ""; }; 88300947291410FC0030B31C /* Markdownosaur.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Markdownosaur.swift; sourceTree = ""; }; 8831F0FF28C65B95009F7682 /* AssetLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetLock.swift; sourceTree = ""; }; 8836AF4328AA293500A94EDD /* CurrencyManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyManagerTests.swift; sourceTree = ""; }; @@ -12712,7 +12710,6 @@ ABAF6F503B172CEE34E19030 /* ReferendumFullDescription */ = { isa = PBXGroup; children = ( - 8830094529140CBF0030B31C /* test.md */, 88300947291410FC0030B31C /* Markdownosaur.swift */, 722DC609FE13ACBEE4328873 /* ReferendumFullDescriptionProtocols.swift */, 57E6825E525785A1A12C62E7 /* ReferendumFullDescriptionWireframe.swift */, @@ -14172,7 +14169,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8830094629140CC00030B31C /* test.md in Resources */, 848E6BE1276328B500C91022 /* PublicSans-Medium.otf in Resources */, 84C1B98D24F55EB200FE5470 /* AccountTableViewCell.xib in Resources */, 849013FC24A92A05008F705E /* novawallet.release.xcconfig in Resources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift index 0b3562b96d..9408f3c17d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift @@ -1,19 +1,40 @@ import UIKit import Markdown -// swiftlint:disable line_length -// swiftlint:disable force_cast -public struct Markdownosaur: MarkupVisitor { - let baseFontSize: CGFloat = 15.0 - let baseTextColor: UIColor = R.color.colorWhite64()! +struct Markdownosaur: MarkupVisitor { + struct Options { + let baseFont: UIFont + let baseTextColor: UIColor + let codeColor: UIColor + let codeFont: UIFont + let numeralFont: UIFont + + init( + baseFont: UIFont = .regularSubheadline, + baseTextColor: UIColor = R.color.colorWhite64()!, + codeColor: UIColor = .systemGray, + codeFont: UIFont = .monospacedSystemFont(ofSize: 14, weight: .regular), + numeralFont: UIFont = .monospacedDigitSystemFont(ofSize: 15, weight: .regular) + ) { + self.baseFont = baseFont + self.baseTextColor = baseTextColor + self.codeColor = codeColor + self.codeFont = codeFont + self.numeralFont = numeralFont + } + } - public init() {} + let options: Options + + init(options: Options) { + self.options = options + } - public mutating func attributedString(from document: Document) -> NSAttributedString { + mutating func attributedString(from document: Document) -> NSAttributedString { visit(document) } - public mutating func defaultVisit(_ markup: Markup) -> NSAttributedString { + mutating func defaultVisit(_ markup: Markup) -> NSAttributedString { let result = NSMutableAttributedString() for child in markup.children { @@ -23,14 +44,17 @@ public struct Markdownosaur: MarkupVisitor { return result } - public mutating func visitText(_ text: Text) -> NSAttributedString { - NSAttributedString(string: text.plainText, attributes: [ - .font: UIFont.systemFont(ofSize: baseFontSize, weight: .regular), - .foregroundColor: baseTextColor - ]) + mutating func visitText(_ text: Text) -> NSAttributedString { + NSAttributedString( + string: text.plainText, + attributes: [ + .font: options.baseFont, + .foregroundColor: options.baseTextColor + ] + ) } - public mutating func visitEmphasis(_ emphasis: Emphasis) -> NSAttributedString { + mutating func visitEmphasis(_ emphasis: Emphasis) -> NSAttributedString { let result = NSMutableAttributedString() for child in emphasis.children { @@ -42,7 +66,7 @@ public struct Markdownosaur: MarkupVisitor { return result } - public mutating func visitStrong(_ strong: Strong) -> NSAttributedString { + mutating func visitStrong(_ strong: Strong) -> NSAttributedString { let result = NSMutableAttributedString() for child in strong.children { @@ -54,7 +78,7 @@ public struct Markdownosaur: MarkupVisitor { return result } - public mutating func visitParagraph(_ paragraph: Paragraph) -> NSAttributedString { + mutating func visitParagraph(_ paragraph: Paragraph) -> NSAttributedString { let result = NSMutableAttributedString() for child in paragraph.children { @@ -62,13 +86,13 @@ public struct Markdownosaur: MarkupVisitor { } if paragraph.hasSuccessor { - result.append(paragraph.isContainedInList ? .singleNewline(withFontSize: baseFontSize) : .doubleNewline(withFontSize: baseFontSize)) + result.append(paragraph.isContainedInList ? .singleNewline(withFont: options.baseFont) : .doubleNewline(withFont: options.baseFont)) } return result } - public mutating func visitHeading(_ heading: Heading) -> NSAttributedString { + mutating func visitHeading(_ heading: Heading) -> NSAttributedString { let result = NSMutableAttributedString() for child in heading.children { @@ -78,41 +102,53 @@ public struct Markdownosaur: MarkupVisitor { result.applyHeading(withLevel: heading.level) if heading.hasSuccessor { - result.append(.doubleNewline(withFontSize: baseFontSize)) + result.append(.doubleNewline(withFont: options.baseFont)) } return result } - public mutating func visitLink(_ link: Link) -> NSAttributedString { + mutating func visitLink(_ link: Link) -> NSAttributedString { let result = NSMutableAttributedString() for child in link.children { result.append(visit(child)) } - let url = link.destination != nil ? URL(string: link.destination!) : nil - - result.applyLink(withURL: url) + if let url = link.destination.map { URL(string: $0) } { + result.applyLink(withURL: url) + } return result } - public mutating func visitInlineCode(_ inlineCode: InlineCode) -> NSAttributedString { - NSAttributedString(string: inlineCode.code, attributes: [.font: UIFont.monospacedSystemFont(ofSize: baseFontSize - 1.0, weight: .regular), .foregroundColor: UIColor.systemGray]) + mutating func visitInlineCode(_ inlineCode: InlineCode) -> NSAttributedString { + NSAttributedString( + string: inlineCode.code, + attributes: [ + .font: options.codeFont, + .foregroundColor: options.codeColor + ] + ) } - public func visitCodeBlock(_ codeBlock: CodeBlock) -> NSAttributedString { - let result = NSMutableAttributedString(string: codeBlock.code, attributes: [.font: UIFont.monospacedSystemFont(ofSize: baseFontSize - 1.0, weight: .regular), .foregroundColor: UIColor.systemGray]) + func visitCodeBlock(_ codeBlock: CodeBlock) -> NSAttributedString { + let result = NSMutableAttributedString( + string: codeBlock.code, + attributes: [ + .font: options.codeFont, + .foregroundColor: options.codeColor + ] + ) if codeBlock.hasSuccessor { - result.append(.singleNewline(withFontSize: baseFontSize)) + result.append(.singleNewline(withFont: options.baseFont)) } return result } - public mutating func visitStrikethrough(_ strikethrough: Strikethrough) -> NSAttributedString { + mutating func visitStrikethrough(_ strikethrough: Strikethrough) -> NSAttributedString { let result = NSMutableAttributedString() for child in strikethrough.children { @@ -124,10 +160,10 @@ public struct Markdownosaur: MarkupVisitor { return result } - public mutating func visitUnorderedList(_ unorderedList: UnorderedList) -> NSAttributedString { + mutating func visitUnorderedList(_ unorderedList: UnorderedList) -> NSAttributedString { let result = NSMutableAttributedString() - let font = UIFont.systemFont(ofSize: baseFontSize, weight: .regular) + let font = options.baseFont for listItem in unorderedList.listItems { var listItemAttributes: [NSAttributedString.Key: Any] = [:] @@ -149,23 +185,24 @@ public struct Markdownosaur: MarkupVisitor { listItemParagraphStyle.headIndent = secondTabLocation listItemAttributes[.paragraphStyle] = listItemParagraphStyle - listItemAttributes[.font] = UIFont.systemFont(ofSize: baseFontSize, weight: .regular) + listItemAttributes[.font] = font listItemAttributes[.listDepth] = unorderedList.listDepth - let listItemAttributedString = visit(listItem).mutableCopy() as! NSMutableAttributedString - listItemAttributedString.insert(NSAttributedString(string: "\t•\t", attributes: listItemAttributes), at: 0) + if let listItemAttributedString = visit(listItem).mutableCopy() as? NSMutableAttributedString { + listItemAttributedString.insert(NSAttributedString(string: "\t•\t", attributes: listItemAttributes), at: 0) - result.append(listItemAttributedString) + result.append(listItemAttributedString) + } } if unorderedList.hasSuccessor { - result.append(.doubleNewline(withFontSize: baseFontSize)) + result.append(.doubleNewline(withFont: font)) } return result } - public mutating func visitListItem(_ listItem: ListItem) -> NSAttributedString { + mutating func visitListItem(_ listItem: ListItem) -> NSAttributedString { let result = NSMutableAttributedString() for child in listItem.children { @@ -173,20 +210,20 @@ public struct Markdownosaur: MarkupVisitor { } if listItem.hasSuccessor { - result.append(.singleNewline(withFontSize: baseFontSize)) + result.append(.singleNewline(withFont: options.baseFont)) } return result } - public mutating func visitOrderedList(_ orderedList: OrderedList) -> NSAttributedString { + mutating func visitOrderedList(_ orderedList: OrderedList) -> NSAttributedString { let result = NSMutableAttributedString() for (index, listItem) in orderedList.listItems.enumerated() { var listItemAttributes: [NSAttributedString.Key: Any] = [:] - let font = UIFont.systemFont(ofSize: baseFontSize, weight: .regular) - let numeralFont = UIFont.monospacedDigitSystemFont(ofSize: baseFontSize, weight: .regular) + let font = options.baseFont + let numeralFont = options.numeralFont let listItemParagraphStyle = NSMutableParagraphStyle() @@ -194,9 +231,13 @@ public struct Markdownosaur: MarkupVisitor { let baseLeftMargin: CGFloat = 15.0 let leftMarginOffset = baseLeftMargin + (20.0 * CGFloat(orderedList.listDepth)) - // Grab the highest number to be displayed and measure its width (yes normally some digits are wider than others but since we're using the numeral mono font all will be the same width in this case) + // Grab the highest number to be displayed and measure its width (yes normally some digits are wider than + // others but since we're using the numeral mono font all will be the same width in this case) let highestNumberInList = orderedList.childCount - let numeralColumnWidth = ceil(NSAttributedString(string: "\(highestNumberInList).", attributes: [.font: numeralFont]).size().width) + let numeralColumnWidth = ceil(NSAttributedString( + string: "\(highestNumberInList).", + attributes: [.font: numeralFont] + ).size().width) let spacingFromIndex: CGFloat = 8.0 let firstTabLocation = leftMarginOffset + numeralColumnWidth @@ -213,26 +254,31 @@ public struct Markdownosaur: MarkupVisitor { listItemAttributes[.font] = font listItemAttributes[.listDepth] = orderedList.listDepth - let listItemAttributedString = visit(listItem).mutableCopy() as! NSMutableAttributedString - - // Same as the normal list attributes, but for prettiness in formatting we want to use the cool monospaced numeral font - var numberAttributes = listItemAttributes - numberAttributes[.font] = numeralFont + if let listItemAttributedString = visit(listItem).mutableCopy() as? NSMutableAttributedString { + // Same as the normal list attributes, but for prettiness in formatting we want to use + // the cool monospaced numeral font + var numberAttributes = listItemAttributes + numberAttributes[.font] = numeralFont - let numberAttributedString = NSAttributedString(string: "\t\(index + 1).\t", attributes: numberAttributes) - listItemAttributedString.insert(numberAttributedString, at: 0) + let numberAttributedString = NSAttributedString( + string: "\t\(index + 1).\t", + attributes: numberAttributes + ) + listItemAttributedString.insert(numberAttributedString, at: 0) - result.append(listItemAttributedString) + result.append(listItemAttributedString) + } } if orderedList.hasSuccessor { - result.append(orderedList.isContainedInList ? .singleNewline(withFontSize: baseFontSize) : .doubleNewline(withFontSize: baseFontSize)) + result.append(orderedList.isContainedInList ? + .singleNewline(withFont: options.baseFont) : .doubleNewline(withFont: options.baseFont)) } return result } - public mutating func visitBlockQuote(_ blockQuote: BlockQuote) -> NSAttributedString { + mutating func visitBlockQuote(_ blockQuote: BlockQuote) -> NSAttributedString { let result = NSMutableAttributedString() for child in blockQuote.children { @@ -248,26 +294,27 @@ public struct Markdownosaur: MarkupVisitor { quoteParagraphStyle.headIndent = leftMarginOffset quoteAttributes[.paragraphStyle] = quoteParagraphStyle - quoteAttributes[.font] = UIFont.systemFont(ofSize: baseFontSize, weight: .regular) + quoteAttributes[.font] = options.baseFont quoteAttributes[.listDepth] = blockQuote.quoteDepth - let quoteAttributedString = visit(child).mutableCopy() as! NSMutableAttributedString - quoteAttributedString.insert(NSAttributedString(string: "\t", attributes: quoteAttributes), at: 0) + if let quoteAttributedString = visit(child).mutableCopy() as? NSMutableAttributedString { + quoteAttributedString.insert(NSAttributedString(string: "\t", attributes: quoteAttributes), at: 0) - quoteAttributedString.addAttribute(.foregroundColor, value: UIColor.systemGray) + quoteAttributedString.addAttribute(.foregroundColor, value: UIColor.systemGray) - result.append(quoteAttributedString) + result.append(quoteAttributedString) + } } if blockQuote.hasSuccessor { - result.append(.doubleNewline(withFontSize: baseFontSize)) + result.append(.doubleNewline(withFont: options.baseFont)) } return result } } -// MARK: - Extensions Land +// MARK: - NSMutableAttributedString Extensions extension NSMutableAttributedString { func applyEmphasis() { @@ -400,14 +447,11 @@ extension Markup { } extension NSAttributedString { - static func singleNewline(withFontSize fontSize: CGFloat) -> NSAttributedString { - NSAttributedString(string: "\n", attributes: [.font: UIFont.systemFont(ofSize: fontSize, weight: .regular)]) + static func singleNewline(withFont font: UIFont) -> NSAttributedString { + NSAttributedString(string: "\n", attributes: [.font: font]) } - static func doubleNewline(withFontSize fontSize: CGFloat) -> NSAttributedString { - NSAttributedString(string: "\n\n", attributes: [.font: UIFont.systemFont(ofSize: fontSize, weight: .regular)]) + static func doubleNewline(withFont font: UIFont) -> NSAttributedString { + NSAttributedString(string: "\n\n", attributes: [.font: font]) } } - -// swiftlint:enable line_length -// swiftlint:enable force_cast diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift index 9dfa0a2ff1..b1ad4bb60e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift @@ -1,4 +1,6 @@ -protocol ReferendumFullDescriptionViewProtocol: ControllerBackedProtocol {} +protocol ReferendumFullDescriptionViewProtocol: ControllerBackedProtocol { + func didReceive(title: String, description: String) +} protocol ReferendumFullDescriptionPresenterProtocol: AnyObject { func setup() diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift index e2715a0b88..66a6df37dc 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift @@ -19,30 +19,15 @@ final class ReferendumFullDescriptionViewController: UIViewController, ViewHolde view = ReferendumFullDescriptionViewLayout() } - // swiftlint:disable line_length override func viewDidLoad() { super.viewDidLoad() presenter.setup() - - guard let markdownText = try? createMarkdownTextSample() else { - return - } - didRecieve( - title: "Polkadot and Kusama participation in the 10th Pais Digital Chile Summit.", - description: markdownText - ) - } - - private func createMarkdownTextSample() throws -> String { - let url = Bundle.main.url(forResource: "test", withExtension: "md")! - let data = try Data(contentsOf: url) - return String(data: data, encoding: .utf8)! } } extension ReferendumFullDescriptionViewController: ReferendumFullDescriptionViewProtocol { - func didRecieve(title: String, description: String) { + func didReceive(title: String, description: String) { rootView.set(title: title) rootView.set(markdownText: description) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift index 2f51f14a58..7bb51900a6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift @@ -45,7 +45,7 @@ final class ReferendumFullDescriptionViewLayout: UIView { func set(markdownText: String) { let document = Document(parsing: markdownText) - var markdownosaur = Markdownosaur() + var markdownosaur = Markdownosaur(options: .init()) descriptionTextView.attributedText = markdownosaur.attributedString(from: document) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/test.md b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/test.md deleted file mode 100644 index 0020528b2c..0000000000 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/test.md +++ /dev/null @@ -1,287 +0,0 @@ -Opening paragraph, with an ordered list of autumn leaves I found - -1. A big leaf -1. Some small leaves: - 1. Red (nested) - 2. **Orange** - 3. Yellow -1. A medium sized leaf that ~~maybe~~ was pancake shaped - -Unordered list of fruits: - -- Blueberries -- Apples - - Macintosh - - Honey crisp - - Cortland -- Banana - -### Fancy Header Title - -Here's what someone said: - -> I think blockquotes are cool - -Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! - -And then they mentiond code around `NSAttributedString` that looked like this code block: - -```swift -func yeah() -> NSAttributedString { - // TODO: Write code -} -``` - -Tables are even supported but (but need more than `NSAttributedString` for support :p) - -Opening paragraph, with an ordered list of autumn leaves I found - -1. A big leaf -1. Some small leaves: - 1. Red (nested) - 2. **Orange** - 3. Yellow -1. A medium sized leaf that ~~maybe~~ was pancake shaped - -Unordered list of fruits: - -- Blueberries -- Apples - - Macintosh - - Honey crisp - - Cortland -- Banana - -### Fancy Header Title - -Here's what someone said: - -> I think blockquotes are cool - -Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! - -And then they mentiond code around `NSAttributedString` that looked like this code block: - -```swift -func yeah() -> NSAttributedString { - // TODO: Write code -} -``` - -Tables are even supported but (but need more than `NSAttributedString` for support :p) - -Opening paragraph, with an ordered list of autumn leaves I found - -1. A big leaf -1. Some small leaves: - 1. Red (nested) - 2. **Orange** - 3. Yellow -1. A medium sized leaf that ~~maybe~~ was pancake shaped - -Unordered list of fruits: - -- Blueberries -- Apples - - Macintosh - - Honey crisp - - Cortland -- Banana - -### Fancy Header Title - -Here's what someone said: - -> I think blockquotes are cool - -Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! - -And then they mentiond code around `NSAttributedString` that looked like this code block: - -```swift -func yeah() -> NSAttributedString { - // TODO: Write code -} -``` - -Tables are even supported but (but need more than `NSAttributedString` for support :p) - -Opening paragraph, with an ordered list of autumn leaves I found - -1. A big leaf -1. Some small leaves: - 1. Red (nested) - 2. **Orange** - 3. Yellow -1. A medium sized leaf that ~~maybe~~ was pancake shaped - -Unordered list of fruits: - -- Blueberries -- Apples - - Macintosh - - Honey crisp - - Cortland -- Banana - -### Fancy Header Title - -Here's what someone said: - -> I think blockquotes are cool - -Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! - -And then they mentiond code around `NSAttributedString` that looked like this code block: - -```swift -func yeah() -> NSAttributedString { - // TODO: Write code -} -``` - -Tables are even supported but (but need more than `NSAttributedString` for support :p) - -Opening paragraph, with an ordered list of autumn leaves I found - -1. A big leaf -1. Some small leaves: - 1. Red (nested) - 2. **Orange** - 3. Yellow -1. A medium sized leaf that ~~maybe~~ was pancake shaped - -Unordered list of fruits: - -- Blueberries -- Apples - - Macintosh - - Honey crisp - - Cortland -- Banana - -### Fancy Header Title - -Here's what someone said: - -> I think blockquotes are cool - -Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! - -And then they mentiond code around `NSAttributedString` that looked like this code block: - -```swift -func yeah() -> NSAttributedString { - // TODO: Write code -} -``` - -Tables are even supported but (but need more than `NSAttributedString` for support :p) - -Opening paragraph, with an ordered list of autumn leaves I found - -1. A big leaf -1. Some small leaves: - 1. Red (nested) - 2. **Orange** - 3. Yellow -1. A medium sized leaf that ~~maybe~~ was pancake shaped - -Unordered list of fruits: - -- Blueberries -- Apples - - Macintosh - - Honey crisp - - Cortland -- Banana - -### Fancy Header Title - -Here's what someone said: - -> I think blockquotes are cool - -Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! - -And then they mentiond code around `NSAttributedString` that looked like this code block: - -```swift -func yeah() -> NSAttributedString { - // TODO: Write code -} -``` - -Tables are even supported but (but need more than `NSAttributedString` for support :p) - -Opening paragraph, with an ordered list of autumn leaves I found - -1. A big leaf -1. Some small leaves: - 1. Red (nested) - 2. **Orange** - 3. Yellow -1. A medium sized leaf that ~~maybe~~ was pancake shaped - -Unordered list of fruits: - -- Blueberries -- Apples - - Macintosh - - Honey crisp - - Cortland -- Banana - -### Fancy Header Title - -Here's what someone said: - -> I think blockquotes are cool - -Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! - -And then they mentiond code around `NSAttributedString` that looked like this code block: - -```swift -func yeah() -> NSAttributedString { - // TODO: Write code -} -``` - -Tables are even supported but (but need more than `NSAttributedString` for support :p) - -Opening paragraph, with an ordered list of autumn leaves I found - -1. A big leaf -1. Some small leaves: - 1. Red (nested) - 2. **Orange** - 3. Yellow -1. A medium sized leaf that ~~maybe~~ was pancake shaped - -Unordered list of fruits: - -- Blueberries -- Apples - - Macintosh - - Honey crisp - - Cortland -- Banana - -### Fancy Header Title - -Here's what someone said: - -> I think blockquotes are cool - -Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! - -And then they mentiond code around `NSAttributedString` that looked like this code block: - -```swift -func yeah() -> NSAttributedString { - // TODO: Write code -} -``` - -Tables are even supported but (but need more than `NSAttributedString` for support :p) From 620ae20caed03b71d1a568200c580b117ecb62d4 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 4 Nov 2022 11:37:45 +0300 Subject: [PATCH 153/229] added image handling --- .../Markdownosaur.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift index 9408f3c17d..a270fcc28b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift @@ -312,6 +312,24 @@ struct Markdownosaur: MarkupVisitor { return result } + + mutating func visitImage(_ image: Image) -> NSAttributedString { + let result = NSMutableAttributedString() + + if + let source = image.source, + let imageURL = URL(string: source), + let imageData = try? Data(contentsOf: imageURL) { + let image = UIImage(data: imageData) + let imageAttachment = NSTextAttachment() + imageAttachment.bounds = CGRect(x: 0, y: 0, width: 50, height: 50) + imageAttachment.image = image + + result.append(NSAttributedString(attachment: imageAttachment)) + } + + return result + } } // MARK: - NSMutableAttributedString Extensions From 56567441c421e1abf7841cf67bd9cfd523718118 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 4 Nov 2022 18:15:14 +0300 Subject: [PATCH 154/229] replace markdown library --- Podfile | 3 +- Podfile.lock | 6 +- novawallet.xcodeproj/project.pbxproj | 31 +- .../xcshareddata/swiftpm/Package.resolved | 23 - .../Markdownosaur.swift | 475 ------------------ .../ReferendumFullDescriptionPresenter.swift | 11 + .../ReferendumFullDescriptionProtocols.swift | 5 +- ...erendumFullDescriptionViewController.swift | 11 + .../ReferendumFullDescriptionViewLayout.swift | 23 +- 9 files changed, 53 insertions(+), 535 deletions(-) delete mode 100644 novawallet.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100644 novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift diff --git a/Podfile b/Podfile index 017173f1a3..1e38447297 100644 --- a/Podfile +++ b/Podfile @@ -22,7 +22,8 @@ abstract_target 'novawalletAll' do pod 'Charts' pod 'SwiftRLP', :git => 'https://github.com/ERussel/SwiftRLP.git' pod 'Starscream', :git => 'https://github.com/ERussel/Starscream.git', :tag => '4.0.5' - + pod 'MarkdownView' + target 'novawalletTests' do inherit! :search_paths diff --git a/Podfile.lock b/Podfile.lock index 6be586d05d..a6bdfa0016 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -39,6 +39,7 @@ PODS: - IrohaCrypto/Common - keccak.c (0.1.3) - Kingfisher (6.3.0) + - MarkdownView (1.9.1) - R.swift (5.4.0): - R.swift.Library (~> 5.3.0) - R.swift.Library (5.3.0) @@ -130,6 +131,7 @@ DEPENDENCIES: - Cuckoo - FireMock - Kingfisher + - MarkdownView - R.swift - ReachabilitySwift - RobinHood (~> 2.6.0) @@ -156,6 +158,7 @@ SPEC REPOS: - IrohaCrypto - keccak.c - Kingfisher + - MarkdownView - R.swift - R.swift.Library - ReachabilitySwift @@ -222,6 +225,7 @@ SPEC CHECKSUMS: IrohaCrypto: 6be75a4268cd1f5cec4231c6d3f95cb03f723fd3 keccak.c: 859583afdaccb4e4fcc0f0096064d101580313f4 Kingfisher: 6c3df386db71d82c0817a429d2c9421a77396529 + MarkdownView: 22249778219cc22901f1454e8355298dd0bda7f0 R.swift: c533450b0f7dc494e0993f5f1a1db925d84c3006 R.swift.Library: 0fc583cb55a99e28901299cc451614cad1161962 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 @@ -244,6 +248,6 @@ SPEC CHECKSUMS: TweetNacl: 3abf4d1d2082b0114e7a67410e300892448951e6 xxHash-Swift: 30bd6a7507b3b7348a277c49b1cb6346c2905ec7 -PODFILE CHECKSUM: 4d0db693ac4524f7e22cfc95b6546c23edf7f2d1 +PODFILE CHECKSUM: f908a1517da883de596e198df70699d46c3496b1 COCOAPODS: 1.11.3 diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index df1a32aa31..cedc63d640 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ @@ -251,8 +251,8 @@ 61B9688494251703A6373A1B /* StakingAmountWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6216F6F1B91F798F07695FB6 /* StakingAmountWireframe.swift */; }; 61E0DC83C1D60D677274D7CE /* AccountExportPasswordViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11575D8B4F64C2E805372A5 /* AccountExportPasswordViewFactory.swift */; }; 623474C49445578F030291B0 /* ParaStkStakeSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0B2C32E11E2F7F3D4A1D3AB /* ParaStkStakeSetupWireframe.swift */; }; - 62B2298F132DB0CE0794DD7A /* ReferendumFullDescriptionWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E6825E525785A1A12C62E7 /* ReferendumFullDescriptionWireframe.swift */; }; 62649D3FB6AACB508872C67A /* GovernanceUnlockConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9638E6EDBA41A5772E0033AE /* GovernanceUnlockConfirmInteractor.swift */; }; + 62B2298F132DB0CE0794DD7A /* ReferendumFullDescriptionWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E6825E525785A1A12C62E7 /* ReferendumFullDescriptionWireframe.swift */; }; 63185C6D67EAEB2867069AB9 /* ParitySignerWelcomeProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CBB8745F8C36BB107625E8F /* ParitySignerWelcomeProtocols.swift */; }; 640A79BD1335394818E70366 /* WalletHistoryFilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6884DFC1AA1B995C21C274C /* WalletHistoryFilterViewController.swift */; }; 641D7CF89F37B1890516015E /* ParitySignerTxScanProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F10F130391C4B3652FE8F59 /* ParitySignerTxScanProtocols.swift */; }; @@ -2280,8 +2280,6 @@ 882C29AA28DC7B3D009CA4B6 /* SubstrateStorageMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882C29A928DC7B3D009CA4B6 /* SubstrateStorageMigrator.swift */; }; 882C29AC28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882C29AB28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift */; }; 882C29AE28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882C29AD28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift */; }; - 88300944291409600030B31C /* Markdown in Frameworks */ = {isa = PBXBuildFile; productRef = 88300943291409600030B31C /* Markdown */; }; - 88300948291410FC0030B31C /* Markdownosaur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88300947291410FC0030B31C /* Markdownosaur.swift */; }; 8831F10028C65B95009F7682 /* AssetLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8831F0FF28C65B95009F7682 /* AssetLock.swift */; }; 8836AF4428AA293500A94EDD /* CurrencyManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8836AF4328AA293500A94EDD /* CurrencyManagerTests.swift */; }; 8836AF4828AA49AB00A94EDD /* Currency+btc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8836AF4728AA49AB00A94EDD /* Currency+btc.swift */; }; @@ -5253,7 +5251,6 @@ 882C29A928DC7B3D009CA4B6 /* SubstrateStorageMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubstrateStorageMigrator.swift; sourceTree = ""; }; 882C29AB28DC7B7F009CA4B6 /* SubstrateStorageVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubstrateStorageVersion.swift; sourceTree = ""; }; 882C29AD28DC7CB4009CA4B6 /* StorageMigrating+CheckVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StorageMigrating+CheckVersion.swift"; sourceTree = ""; }; - 88300947291410FC0030B31C /* Markdownosaur.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Markdownosaur.swift; sourceTree = ""; }; 8831F0FF28C65B95009F7682 /* AssetLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetLock.swift; sourceTree = ""; }; 8836AF4328AA293500A94EDD /* CurrencyManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyManagerTests.swift; sourceTree = ""; }; 8836AF4728AA49AB00A94EDD /* Currency+btc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Currency+btc.swift"; sourceTree = ""; }; @@ -5915,7 +5912,6 @@ buildActionMask = 2147483647; files = ( 352B75BEB10A48CC6CE64D4A /* Pods_novawalletAll_novawallet.framework in Frameworks */, - 88300944291409600030B31C /* Markdown in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -12769,7 +12765,6 @@ ABAF6F503B172CEE34E19030 /* ReferendumFullDescription */ = { isa = PBXGroup; children = ( - 88300947291410FC0030B31C /* Markdownosaur.swift */, 722DC609FE13ACBEE4328873 /* ReferendumFullDescriptionProtocols.swift */, 57E6825E525785A1A12C62E7 /* ReferendumFullDescriptionWireframe.swift */, CAEF44ADECD66B49E3430365 /* ReferendumFullDescriptionPresenter.swift */, @@ -14141,7 +14136,6 @@ ); name = novawallet; packageProductDependencies = ( - 88300943291409600030B31C /* Markdown */, ); productName = fearless; productReference = 849013A824A80984008F705E /* novawallet.app */; @@ -14203,7 +14197,6 @@ ); mainGroup = 8490139F24A80984008F705E; packageReferences = ( - 88300942291409600030B31C /* XCRemoteSwiftPackageReference "swift-markdown" */, ); productRefGroup = 849013A924A80984008F705E /* Products */; projectDirPath = ""; @@ -16044,7 +16037,6 @@ 8428228A289B1E5C00163031 /* TableHeaderLayoutUpdatable.swift in Sources */, 84EE2FAF2891215200A98816 /* WalletManageTableViewCell.swift in Sources */, 849B563527A70DDE007D5528 /* ExtrinsicProcessor+Matching.swift in Sources */, - 88300948291410FC0030B31C /* Markdownosaur.swift in Sources */, 94B0F0C84AF74B3CD7223C3A /* AccountConfirmPresenter.swift in Sources */, 8468B87224F63D3A00B76BC6 /* AddAccount+AccountCreateWireframe.swift in Sources */, 9DFB37659A6B911A4D54623E /* AccountConfirmInteractor.swift in Sources */, @@ -18056,25 +18048,6 @@ }; /* End XCConfigurationList section */ -/* Begin XCRemoteSwiftPackageReference section */ - 88300942291409600030B31C /* XCRemoteSwiftPackageReference "swift-markdown" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/apple/swift-markdown.git"; - requirement = { - branch = main; - kind = branch; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 88300943291409600030B31C /* Markdown */ = { - isa = XCSwiftPackageProductDependency; - package = 88300942291409600030B31C /* XCRemoteSwiftPackageReference "swift-markdown" */; - productName = Markdown; - }; -/* End XCSwiftPackageProductDependency section */ - /* Begin XCVersionGroup section */ 843910CA253F7E6500E3C217 /* SubstrateDataModel.xcdatamodeld */ = { isa = XCVersionGroup; diff --git a/novawallet.xcworkspace/xcshareddata/swiftpm/Package.resolved b/novawallet.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index b854da4a43..0000000000 --- a/novawallet.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,23 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-cmark", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-cmark.git", - "state" : { - "branch" : "gfm", - "revision" : "bfdc057b5a02fc65af20771a7ba08f9c944eb117" - } - }, - { - "identity" : "swift-markdown", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-markdown.git", - "state" : { - "branch" : "main", - "revision" : "d491147940587dbadfb3472354f4d0c6e063e061" - } - } - ], - "version" : 2 -} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift deleted file mode 100644 index a270fcc28b..0000000000 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/Markdownosaur.swift +++ /dev/null @@ -1,475 +0,0 @@ -import UIKit -import Markdown - -struct Markdownosaur: MarkupVisitor { - struct Options { - let baseFont: UIFont - let baseTextColor: UIColor - let codeColor: UIColor - let codeFont: UIFont - let numeralFont: UIFont - - init( - baseFont: UIFont = .regularSubheadline, - baseTextColor: UIColor = R.color.colorWhite64()!, - codeColor: UIColor = .systemGray, - codeFont: UIFont = .monospacedSystemFont(ofSize: 14, weight: .regular), - numeralFont: UIFont = .monospacedDigitSystemFont(ofSize: 15, weight: .regular) - ) { - self.baseFont = baseFont - self.baseTextColor = baseTextColor - self.codeColor = codeColor - self.codeFont = codeFont - self.numeralFont = numeralFont - } - } - - let options: Options - - init(options: Options) { - self.options = options - } - - mutating func attributedString(from document: Document) -> NSAttributedString { - visit(document) - } - - mutating func defaultVisit(_ markup: Markup) -> NSAttributedString { - let result = NSMutableAttributedString() - - for child in markup.children { - result.append(visit(child)) - } - - return result - } - - mutating func visitText(_ text: Text) -> NSAttributedString { - NSAttributedString( - string: text.plainText, - attributes: [ - .font: options.baseFont, - .foregroundColor: options.baseTextColor - ] - ) - } - - mutating func visitEmphasis(_ emphasis: Emphasis) -> NSAttributedString { - let result = NSMutableAttributedString() - - for child in emphasis.children { - result.append(visit(child)) - } - - result.applyEmphasis() - - return result - } - - mutating func visitStrong(_ strong: Strong) -> NSAttributedString { - let result = NSMutableAttributedString() - - for child in strong.children { - result.append(visit(child)) - } - - result.applyStrong() - - return result - } - - mutating func visitParagraph(_ paragraph: Paragraph) -> NSAttributedString { - let result = NSMutableAttributedString() - - for child in paragraph.children { - result.append(visit(child)) - } - - if paragraph.hasSuccessor { - result.append(paragraph.isContainedInList ? .singleNewline(withFont: options.baseFont) : .doubleNewline(withFont: options.baseFont)) - } - - return result - } - - mutating func visitHeading(_ heading: Heading) -> NSAttributedString { - let result = NSMutableAttributedString() - - for child in heading.children { - result.append(visit(child)) - } - - result.applyHeading(withLevel: heading.level) - - if heading.hasSuccessor { - result.append(.doubleNewline(withFont: options.baseFont)) - } - - return result - } - - mutating func visitLink(_ link: Link) -> NSAttributedString { - let result = NSMutableAttributedString() - - for child in link.children { - result.append(visit(child)) - } - - if let url = link.destination.map { URL(string: $0) } { - result.applyLink(withURL: url) - } - - return result - } - - mutating func visitInlineCode(_ inlineCode: InlineCode) -> NSAttributedString { - NSAttributedString( - string: inlineCode.code, - attributes: [ - .font: options.codeFont, - .foregroundColor: options.codeColor - ] - ) - } - - func visitCodeBlock(_ codeBlock: CodeBlock) -> NSAttributedString { - let result = NSMutableAttributedString( - string: codeBlock.code, - attributes: [ - .font: options.codeFont, - .foregroundColor: options.codeColor - ] - ) - - if codeBlock.hasSuccessor { - result.append(.singleNewline(withFont: options.baseFont)) - } - - return result - } - - mutating func visitStrikethrough(_ strikethrough: Strikethrough) -> NSAttributedString { - let result = NSMutableAttributedString() - - for child in strikethrough.children { - result.append(visit(child)) - } - - result.applyStrikethrough() - - return result - } - - mutating func visitUnorderedList(_ unorderedList: UnorderedList) -> NSAttributedString { - let result = NSMutableAttributedString() - - let font = options.baseFont - - for listItem in unorderedList.listItems { - var listItemAttributes: [NSAttributedString.Key: Any] = [:] - - let listItemParagraphStyle = NSMutableParagraphStyle() - - let baseLeftMargin: CGFloat = 15.0 - let leftMarginOffset = baseLeftMargin + (20.0 * CGFloat(unorderedList.listDepth)) - let spacingFromIndex: CGFloat = 8.0 - let bulletWidth = ceil(NSAttributedString(string: "•", attributes: [.font: font]).size().width) - let firstTabLocation = leftMarginOffset + bulletWidth - let secondTabLocation = firstTabLocation + spacingFromIndex - - listItemParagraphStyle.tabStops = [ - NSTextTab(textAlignment: .right, location: firstTabLocation), - NSTextTab(textAlignment: .left, location: secondTabLocation) - ] - - listItemParagraphStyle.headIndent = secondTabLocation - - listItemAttributes[.paragraphStyle] = listItemParagraphStyle - listItemAttributes[.font] = font - listItemAttributes[.listDepth] = unorderedList.listDepth - - if let listItemAttributedString = visit(listItem).mutableCopy() as? NSMutableAttributedString { - listItemAttributedString.insert(NSAttributedString(string: "\t•\t", attributes: listItemAttributes), at: 0) - - result.append(listItemAttributedString) - } - } - - if unorderedList.hasSuccessor { - result.append(.doubleNewline(withFont: font)) - } - - return result - } - - mutating func visitListItem(_ listItem: ListItem) -> NSAttributedString { - let result = NSMutableAttributedString() - - for child in listItem.children { - result.append(visit(child)) - } - - if listItem.hasSuccessor { - result.append(.singleNewline(withFont: options.baseFont)) - } - - return result - } - - mutating func visitOrderedList(_ orderedList: OrderedList) -> NSAttributedString { - let result = NSMutableAttributedString() - - for (index, listItem) in orderedList.listItems.enumerated() { - var listItemAttributes: [NSAttributedString.Key: Any] = [:] - - let font = options.baseFont - let numeralFont = options.numeralFont - - let listItemParagraphStyle = NSMutableParagraphStyle() - - // Implement a base amount to be spaced from the left side at all times to better visually differentiate it as a list - let baseLeftMargin: CGFloat = 15.0 - let leftMarginOffset = baseLeftMargin + (20.0 * CGFloat(orderedList.listDepth)) - - // Grab the highest number to be displayed and measure its width (yes normally some digits are wider than - // others but since we're using the numeral mono font all will be the same width in this case) - let highestNumberInList = orderedList.childCount - let numeralColumnWidth = ceil(NSAttributedString( - string: "\(highestNumberInList).", - attributes: [.font: numeralFont] - ).size().width) - - let spacingFromIndex: CGFloat = 8.0 - let firstTabLocation = leftMarginOffset + numeralColumnWidth - let secondTabLocation = firstTabLocation + spacingFromIndex - - listItemParagraphStyle.tabStops = [ - NSTextTab(textAlignment: .right, location: firstTabLocation), - NSTextTab(textAlignment: .left, location: secondTabLocation) - ] - - listItemParagraphStyle.headIndent = secondTabLocation - - listItemAttributes[.paragraphStyle] = listItemParagraphStyle - listItemAttributes[.font] = font - listItemAttributes[.listDepth] = orderedList.listDepth - - if let listItemAttributedString = visit(listItem).mutableCopy() as? NSMutableAttributedString { - // Same as the normal list attributes, but for prettiness in formatting we want to use - // the cool monospaced numeral font - var numberAttributes = listItemAttributes - numberAttributes[.font] = numeralFont - - let numberAttributedString = NSAttributedString( - string: "\t\(index + 1).\t", - attributes: numberAttributes - ) - listItemAttributedString.insert(numberAttributedString, at: 0) - - result.append(listItemAttributedString) - } - } - - if orderedList.hasSuccessor { - result.append(orderedList.isContainedInList ? - .singleNewline(withFont: options.baseFont) : .doubleNewline(withFont: options.baseFont)) - } - - return result - } - - mutating func visitBlockQuote(_ blockQuote: BlockQuote) -> NSAttributedString { - let result = NSMutableAttributedString() - - for child in blockQuote.children { - var quoteAttributes: [NSAttributedString.Key: Any] = [:] - - let quoteParagraphStyle = NSMutableParagraphStyle() - - let baseLeftMargin: CGFloat = 15.0 - let leftMarginOffset = baseLeftMargin + (20.0 * CGFloat(blockQuote.quoteDepth)) - - quoteParagraphStyle.tabStops = [NSTextTab(textAlignment: .left, location: leftMarginOffset)] - - quoteParagraphStyle.headIndent = leftMarginOffset - - quoteAttributes[.paragraphStyle] = quoteParagraphStyle - quoteAttributes[.font] = options.baseFont - quoteAttributes[.listDepth] = blockQuote.quoteDepth - - if let quoteAttributedString = visit(child).mutableCopy() as? NSMutableAttributedString { - quoteAttributedString.insert(NSAttributedString(string: "\t", attributes: quoteAttributes), at: 0) - - quoteAttributedString.addAttribute(.foregroundColor, value: UIColor.systemGray) - - result.append(quoteAttributedString) - } - } - - if blockQuote.hasSuccessor { - result.append(.doubleNewline(withFont: options.baseFont)) - } - - return result - } - - mutating func visitImage(_ image: Image) -> NSAttributedString { - let result = NSMutableAttributedString() - - if - let source = image.source, - let imageURL = URL(string: source), - let imageData = try? Data(contentsOf: imageURL) { - let image = UIImage(data: imageData) - let imageAttachment = NSTextAttachment() - imageAttachment.bounds = CGRect(x: 0, y: 0, width: 50, height: 50) - imageAttachment.image = image - - result.append(NSAttributedString(attachment: imageAttachment)) - } - - return result - } -} - -// MARK: - NSMutableAttributedString Extensions - -extension NSMutableAttributedString { - func applyEmphasis() { - enumerateAttribute(.font, in: NSRange(location: 0, length: length), options: []) { value, range, _ in - guard let font = value as? UIFont else { return } - - let newFont = font.apply(newTraits: .traitItalic) - addAttribute(.font, value: newFont, range: range) - } - } - - func applyStrong() { - enumerateAttribute(.font, in: NSRange(location: 0, length: length), options: []) { value, range, _ in - guard let font = value as? UIFont else { return } - - let newFont = font.apply(newTraits: .traitBold) - addAttribute(.font, value: newFont, range: range) - } - } - - func applyLink(withURL url: URL?) { - addAttribute(.foregroundColor, value: UIColor.systemBlue) - - if let url = url { - addAttribute(.link, value: url) - } - } - - func applyBlockquote() { - addAttribute(.foregroundColor, value: UIColor.systemGray) - } - - func applyHeading(withLevel headingLevel: Int) { - enumerateAttribute(.font, in: NSRange(location: 0, length: length), options: []) { value, range, _ in - guard let font = value as? UIFont else { return } - - let newFont = font.apply(newTraits: .traitBold, newPointSize: 28.0 - CGFloat(headingLevel * 2)) - addAttribute(.font, value: newFont, range: range) - } - } - - func applyStrikethrough() { - addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue) - } -} - -extension UIFont { - func apply(newTraits: UIFontDescriptor.SymbolicTraits, newPointSize: CGFloat? = nil) -> UIFont { - var existingTraits = fontDescriptor.symbolicTraits - existingTraits.insert(newTraits) - - guard let newFontDescriptor = fontDescriptor.withSymbolicTraits(existingTraits) else { return self } - return UIFont(descriptor: newFontDescriptor, size: newPointSize ?? pointSize) - } -} - -extension ListItemContainer { - /// Depth of the list if nested within others. Index starts at 0. - var listDepth: Int { - var index = 0 - - var currentElement = parent - - while currentElement != nil { - if currentElement is ListItemContainer { - index += 1 - } - - currentElement = currentElement?.parent - } - - return index - } -} - -extension BlockQuote { - /// Depth of the quote if nested within others. Index starts at 0. - var quoteDepth: Int { - var index = 0 - - var currentElement = parent - - while currentElement != nil { - if currentElement is BlockQuote { - index += 1 - } - - currentElement = currentElement?.parent - } - - return index - } -} - -extension NSAttributedString.Key { - static let listDepth = NSAttributedString.Key("ListDepth") - static let quoteDepth = NSAttributedString.Key("QuoteDepth") -} - -extension NSMutableAttributedString { - func addAttribute(_ name: NSAttributedString.Key, value: Any) { - addAttribute(name, value: value, range: NSRange(location: 0, length: length)) - } - - func addAttributes(_ attrs: [NSAttributedString.Key: Any]) { - addAttributes(attrs, range: NSRange(location: 0, length: length)) - } -} - -extension Markup { - /// Returns true if this element has sibling elements after it. - var hasSuccessor: Bool { - guard let childCount = parent?.childCount else { return false } - return indexInParent < childCount - 1 - } - - var isContainedInList: Bool { - var currentElement = parent - - while currentElement != nil { - if currentElement is ListItemContainer { - return true - } - - currentElement = currentElement?.parent - } - - return false - } -} - -extension NSAttributedString { - static func singleNewline(withFont font: UIFont) -> NSAttributedString { - NSAttributedString(string: "\n", attributes: [.font: font]) - } - - static func doubleNewline(withFont font: UIFont) -> NSAttributedString { - NSAttributedString(string: "\n\n", attributes: [.font: font]) - } -} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift index b76af26969..f37f81df68 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift @@ -16,6 +16,17 @@ final class ReferendumFullDescriptionPresenter { extension ReferendumFullDescriptionPresenter: ReferendumFullDescriptionPresenterProtocol { func setup() {} + + func open(url: URL) { + guard let view = view else { + return + } + wireframe.showWeb( + url: url, + from: view, + style: .modal + ) + } } extension ReferendumFullDescriptionPresenter: ReferendumFullDescriptionInteractorOutputProtocol {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift index b1ad4bb60e..d5e0b2b8a4 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionProtocols.swift @@ -1,13 +1,16 @@ +import Foundation + protocol ReferendumFullDescriptionViewProtocol: ControllerBackedProtocol { func didReceive(title: String, description: String) } protocol ReferendumFullDescriptionPresenterProtocol: AnyObject { func setup() + func open(url: URL) } protocol ReferendumFullDescriptionInteractorInputProtocol: AnyObject {} protocol ReferendumFullDescriptionInteractorOutputProtocol: AnyObject {} -protocol ReferendumFullDescriptionWireframeProtocol: AnyObject {} +protocol ReferendumFullDescriptionWireframeProtocol: WebPresentable {} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift index 66a6df37dc..a0c302171b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift @@ -22,8 +22,19 @@ final class ReferendumFullDescriptionViewController: UIViewController, ViewHolde override func viewDidLoad() { super.viewDidLoad() + setupHandlers() presenter.setup() } + + private func setupHandlers() { + rootView.markdownView.onTouchLink = { [weak self] request in + guard let url = request.url, url.scheme == "https" else { + return false + } + self?.presenter.open(url: url) + return false + } + } } extension ReferendumFullDescriptionViewController: ReferendumFullDescriptionViewProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift index 7bb51900a6..e60d05b9c0 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift @@ -1,5 +1,5 @@ import UIKit -import Markdown +import MarkdownView final class ReferendumFullDescriptionViewLayout: UIView { let containerView: ScrollableContainerView = { @@ -26,6 +26,8 @@ final class ReferendumFullDescriptionViewLayout: UIView { $0.textContainer.lineFragmentPadding = 0 } + let markdownView = MarkdownView() + override init(frame: CGRect) { super.init(frame: frame) @@ -34,7 +36,7 @@ final class ReferendumFullDescriptionViewLayout: UIView { $0.edges.equalToSuperview() } containerView.stackView.addArrangedSubview(titleLabel) - containerView.stackView.addArrangedSubview(descriptionTextView) + containerView.stackView.addArrangedSubview(markdownView) containerView.stackView.setCustomSpacing(16, after: titleLabel) } @@ -44,12 +46,23 @@ final class ReferendumFullDescriptionViewLayout: UIView { } func set(markdownText: String) { - let document = Document(parsing: markdownText) - var markdownosaur = Markdownosaur(options: .init()) - descriptionTextView.attributedText = markdownosaur.attributedString(from: document) + markdownView.load(markdown: markdownText, enableImage: true, plugins: plugins()) } func set(title: String) { titleLabel.text = title } + + private func plugins() -> [String]? { + [ + URL(string: "https://cdnjs.cloudflare.com/ajax/libs/markdown-it-footnote/3.0.3/markdown-it-footnote.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-sub@1.0.0/index.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-sup@1.0.0/index.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-ins@3.0.1/dist/markdown-it-ins.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-mark@3.0.1/dist/markdown-it-mark.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-container@3.0.0/dist/markdown-it-container.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-deflist@2.1.0/dist/markdown-it-deflist.min.js") + ].compactMap { $0 } + .compactMap { try? String(contentsOf: $0, encoding: .utf8) } + } } From b3428df2dc71154ce7d9166626b06a6f676a514a Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 4 Nov 2022 18:51:38 +0300 Subject: [PATCH 155/229] added css --- .../ReferendumFullDescriptionViewLayout.swift | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift index e60d05b9c0..c0d1c619fe 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift @@ -16,16 +16,6 @@ final class ReferendumFullDescriptionViewLayout: UIView { $0.numberOfLines = 0 } - let descriptionTextView: UITextView = .create { - $0.backgroundColor = .clear - $0.textColor = R.color.colorWhite64() - $0.font = .regularSubheadline - $0.isScrollEnabled = false - $0.isEditable = false - $0.textContainerInset = .zero - $0.textContainer.lineFragmentPadding = 0 - } - let markdownView = MarkdownView() override init(frame: CGRect) { @@ -46,7 +36,11 @@ final class ReferendumFullDescriptionViewLayout: UIView { } func set(markdownText: String) { - markdownView.load(markdown: markdownText, enableImage: true, plugins: plugins()) + markdownView.load( + markdown: markdownText, + css: css(), + plugins: plugins() + ) } func set(title: String) { @@ -65,4 +59,11 @@ final class ReferendumFullDescriptionViewLayout: UIView { ].compactMap { $0 } .compactMap { try? String(contentsOf: $0, encoding: .utf8) } } + + private func css() -> String? { + guard let color = R.color.colorNovaBlue()?.hexRGB else { + return nil + } + return "a { color: \(color); }" + } } From 85122209f38bf9b61151d83901f9068a18bfdce7 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 5 Nov 2022 13:06:00 +0500 Subject: [PATCH 156/229] add gov1 operation factory --- novawallet.xcodeproj/project.pbxproj | 44 ++++ .../Democracy/Democracy+CodingPath.swift | 11 + .../Democracy/Democracy+ConstantPath.swift | 11 + .../Substrate/Types/Democracy/Democracy.swift | 3 + .../Types/Democracy/DemocracyReferendum.swift | 56 +++++ .../Democracy/DemocracyVoteThreshold.swift | 32 +++ .../Types/Democracy/DemocracyVoting.swift | 43 ++++ .../DemocracyDecidingFunctionProtocol.swift | 96 +++++++++ .../Governance/Model/ReferendumLocal.swift | 32 ++- .../Operation/Gov1LocalMappingFactory.swift | 72 +++++++ .../Gov1OperationFactory+Protocol.swift | 198 ++++++++++++++++++ .../Operation/Gov1OperationFactory.swift | 103 ++++++++- 12 files changed, 692 insertions(+), 9 deletions(-) create mode 100644 novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift create mode 100644 novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift create mode 100644 novawallet/Common/Substrate/Types/Democracy/Democracy.swift create mode 100644 novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift create mode 100644 novawallet/Common/Substrate/Types/Democracy/DemocracyVoteThreshold.swift create mode 100644 novawallet/Common/Substrate/Types/Democracy/DemocracyVoting.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index ddf722740d..e36e233400 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -952,6 +952,15 @@ 845AADA12902D02400B5AE96 /* TitleValueDiffView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845AADA02902D02400B5AE96 /* TitleValueDiffView.swift */; }; 845AADA32902D1EB00B5AE96 /* StackTitleValueDiffCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845AADA22902D1EA00B5AE96 /* StackTitleValueDiffCell.swift */; }; 845AADA62903B32E00B5AE96 /* ReferendumVoteConfirmError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845AADA52903B32E00B5AE96 /* ReferendumVoteConfirmError.swift */; }; + 845B07EB29159190005785D3 /* Democracy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07EA29159190005785D3 /* Democracy.swift */; }; + 845B07ED291594E1005785D3 /* DemocracyReferendum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07EC291594E1005785D3 /* DemocracyReferendum.swift */; }; + 845B07EF2915951A005785D3 /* DemocracyVoteThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07EE2915951A005785D3 /* DemocracyVoteThreshold.swift */; }; + 845B07F129159AE7005785D3 /* DemocracyVoting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07F029159AE7005785D3 /* DemocracyVoting.swift */; }; + 845B07F329159C15005785D3 /* Democracy+CodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07F229159C15005785D3 /* Democracy+CodingPath.swift */; }; + 845B07F5291627A3005785D3 /* Gov1OperationFactory+Protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07F4291627A3005785D3 /* Gov1OperationFactory+Protocol.swift */; }; + 845B07F729162AB3005785D3 /* Democracy+ConstantPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07F629162AB3005785D3 /* Democracy+ConstantPath.swift */; }; + 845B07F929162D24005785D3 /* Gov1LocalMappingFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */; }; + 845B07FD291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */; }; 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811128F429BB0040CE84 /* SupportPallet.swift */; }; 845B811528F43C350040CE84 /* Treasury.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811428F43C350040CE84 /* Treasury.swift */; }; 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811628F43C730040CE84 /* TreasuryProposal.swift */; }; @@ -3906,6 +3915,15 @@ 845AADA02902D02400B5AE96 /* TitleValueDiffView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleValueDiffView.swift; sourceTree = ""; }; 845AADA22902D1EA00B5AE96 /* StackTitleValueDiffCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackTitleValueDiffCell.swift; sourceTree = ""; }; 845AADA52903B32E00B5AE96 /* ReferendumVoteConfirmError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmError.swift; sourceTree = ""; }; + 845B07EA29159190005785D3 /* Democracy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Democracy.swift; sourceTree = ""; }; + 845B07EC291594E1005785D3 /* DemocracyReferendum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemocracyReferendum.swift; sourceTree = ""; }; + 845B07EE2915951A005785D3 /* DemocracyVoteThreshold.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemocracyVoteThreshold.swift; sourceTree = ""; }; + 845B07F029159AE7005785D3 /* DemocracyVoting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemocracyVoting.swift; sourceTree = ""; }; + 845B07F229159C15005785D3 /* Democracy+CodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Democracy+CodingPath.swift"; sourceTree = ""; }; + 845B07F4291627A3005785D3 /* Gov1OperationFactory+Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gov1OperationFactory+Protocol.swift"; sourceTree = ""; }; + 845B07F629162AB3005785D3 /* Democracy+ConstantPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Democracy+ConstantPath.swift"; sourceTree = ""; }; + 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1LocalMappingFactory.swift; sourceTree = ""; }; + 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemocracyDecidingFunctionProtocol.swift; sourceTree = ""; }; 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; @@ -7568,6 +7586,7 @@ 8438E1DC24C18F11001BDB13 /* Types */ = { isa = PBXGroup; children = ( + 845B07E929159174005785D3 /* Democracy */, 84B6349B28F4A05A00503306 /* Preimage */, 845B811328F43C1E0040CE84 /* Treasury */, 845B811028F429AB0040CE84 /* Support */, @@ -8082,6 +8101,19 @@ path = Model; sourceTree = ""; }; + 845B07E929159174005785D3 /* Democracy */ = { + isa = PBXGroup; + children = ( + 845B07EA29159190005785D3 /* Democracy.swift */, + 845B07EC291594E1005785D3 /* DemocracyReferendum.swift */, + 845B07EE2915951A005785D3 /* DemocracyVoteThreshold.swift */, + 845B07F029159AE7005785D3 /* DemocracyVoting.swift */, + 845B07F229159C15005785D3 /* Democracy+CodingPath.swift */, + 845B07F629162AB3005785D3 /* Democracy+ConstantPath.swift */, + ); + path = Democracy; + sourceTree = ""; + }; 845B811028F429AB0040CE84 /* Support */ = { isa = PBXGroup; children = ( @@ -10325,6 +10357,8 @@ 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, 8438432D2913B3150048595C /* Gov1OperationFactory.swift */, 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */, + 845B07F4291627A3005785D3 /* Gov1OperationFactory+Protocol.swift */, + 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */, 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */, 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */, @@ -11628,6 +11662,7 @@ 84F1D67029068F810050F4E3 /* GovernanceDApp.swift */, 843461E7290BF14400379936 /* ReferendumsSorting.swift */, 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */, + 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */, ); path = Model; sourceTree = ""; @@ -15066,6 +15101,7 @@ AE7129B4260872ED000AA3F5 /* EraStakersInfoChanged.swift in Sources */, 842D1E9624D2DD6700C30A7A /* MnemonicDisplayView.swift in Sources */, 8411707A285B10F5006F4DFB /* XcmAssetTransferFee.swift in Sources */, + 845B07F729162AB3005785D3 /* Democracy+ConstantPath.swift in Sources */, 84DBEA56265ED62700FDF73C /* BaseErrorPresentable.swift in Sources */, 845B811928F43D4C0040CE84 /* Treasury+CodingPath.swift in Sources */, 842876B224AE059700D91AD8 /* SupportData.swift in Sources */, @@ -15297,6 +15333,7 @@ 88C7165A28C8D3450015D1E9 /* LocksHeaderView.swift in Sources */, 840B3D6E289A56BA00DA1DA9 /* ParitySignerScanWireframe.swift in Sources */, F48EB5462722BB7000AE15ED /* AcalaBonusService.swift in Sources */, + 845B07ED291594E1005785D3 /* DemocracyReferendum.swift in Sources */, 84466B4028B77B4500FA1E0D /* SignatureVerificationWrapper.swift in Sources */, 844DBC62274D1E29009F8351 /* SecretTypeTableViewCell.swift in Sources */, 847297A2260B3146009B86D0 /* ChangeTargetsSelectValidatorsStartWireframe.swift in Sources */, @@ -15955,6 +15992,7 @@ 8442003628EA9DF100C49C4A /* VoteViewFactory.swift in Sources */, 84BC7041289DBF62008A9758 /* QRDisplayView.swift in Sources */, 2AC7BC7E2731604C001D99B0 /* ChainAccountChanged.swift in Sources */, + 845B07F329159C15005785D3 /* Democracy+CodingPath.swift in Sources */, 847C96492553614F002D288F /* ExportRestoreJsonPresenter.swift in Sources */, 8463A71225E30C95003B8160 /* BalanceViewModelFactory.swift in Sources */, 84A04622277DE83E000B24DA /* DAppListErrorView.swift in Sources */, @@ -16193,6 +16231,7 @@ 8401AEC62642A71D000B03E3 /* StakingRebondConfirmationLayout.swift in Sources */, 8487584327F08F9600495306 /* AddressScanPresenter.swift in Sources */, 847F2D5127AAB4BC00AFD476 /* GradientModel.swift in Sources */, + 845B07FD291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift in Sources */, 84981CC32666D95F00C4C691 /* GradientButton+Style.swift in Sources */, 84E258A12892CC0F00DC8A51 /* AccountManagementViewLayout.swift in Sources */, 848FD1A528AE27E700CCD9E2 /* HardwareWalletOption.swift in Sources */, @@ -16209,6 +16248,7 @@ 8473D4212657FFFB00B394B2 /* Crowdloan.swift in Sources */, 843461F7290E4AF500379936 /* Gov2UnlocksCalculator.swift in Sources */, 849E17E327913220002D1744 /* DAppSearchResult.swift in Sources */, + 845B07EB29159190005785D3 /* Democracy.swift in Sources */, 844CB57626FA064700396E13 /* ChainRegistryError.swift in Sources */, 842A737327DB7F75006EE1EA /* OperationRewardViewModel.swift in Sources */, 84CA68CF26BD6872003B9453 /* RuntimeSyncService.swift in Sources */, @@ -16403,6 +16443,7 @@ 84F6B6502619E1ED0038F10D /* Int+Operations.swift in Sources */, 8487010E2907DF2F00F2C0C3 /* MultiValueView+Styles.swift in Sources */, 85547F698B551ACD387D84E2 /* SelectValidatorsStartViewController.swift in Sources */, + 845B07F129159AE7005785D3 /* DemocracyVoting.swift in Sources */, 41B29C1C9239BB2DCB7903A7 /* SelectValidatorsStartViewFactory.swift in Sources */, 25381484F16FB930B8A90CE3 /* SelectValidatorsConfirmProtocols.swift in Sources */, B02EAF42C91E069FE6872EE0 /* SelectValidatorsConfirmWireframe.swift in Sources */, @@ -16574,6 +16615,7 @@ 8489A6CE27FC5C5E0040C066 /* StakingActionsView.swift in Sources */, 84DED40B266656D400A153BB /* KaruraBonusService.swift in Sources */, 842A736627DB485E006EE1EA /* OperationSlashModel.swift in Sources */, + 845B07EF2915951A005785D3 /* DemocracyVoteThreshold.swift in Sources */, 885551F78A5926D16D5AF0CB /* ControllerAccountPresenter.swift in Sources */, 8442002F28E9AEFB00C49C4A /* VoteWireframe.swift in Sources */, 841E553C282D44BA00C8438F /* ParachainStakingAccountSubscriptionService.swift in Sources */, @@ -17056,6 +17098,7 @@ 2F6FA089995FD12FB2AA814B /* ParitySignerWelcomePresenter.swift in Sources */, 012AE9F8BDA682C691B6F9FD /* ParitySignerWelcomeViewController.swift in Sources */, DC2867A7DC1415052D090C53 /* ParitySignerWelcomeViewLayout.swift in Sources */, + 845B07F5291627A3005785D3 /* Gov1OperationFactory+Protocol.swift in Sources */, 97608590E8D770A86CCFBE86 /* ParitySignerWelcomeViewFactory.swift in Sources */, 8425D0E028FE738D003B782A /* ReferendumVoteSetupInteractorError.swift in Sources */, 5443122935BBFDD55AE9E6FD /* ParitySignerAddressesProtocols.swift in Sources */, @@ -17098,6 +17141,7 @@ 30542C0BD486FD1583F36BA2 /* LedgerNetworkSelectionProtocols.swift in Sources */, 84F1D66D29051F240050F4E3 /* ReferendumReuseLockModel.swift in Sources */, 84FBDBE128C884DA00CC1037 /* ParaStkYieldBoostStorageSubscriber.swift in Sources */, + 845B07F929162D24005785D3 /* Gov1LocalMappingFactory.swift in Sources */, C102544345E604976BF7AFFC /* LedgerNetworkSelectionWireframe.swift in Sources */, D71B2C6056D803C196DF4CDA /* LedgerNetworkSelectionPresenter.swift in Sources */, 19D3739A3C7800A5A18DA41C /* LedgerNetworkSelectionInteractor.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift b/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift new file mode 100644 index 0000000000..f9a4453fe7 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift @@ -0,0 +1,11 @@ +import Foundation + +extension Democracy { + static var referendumInfo: StorageCodingPath { + StorageCodingPath(moduleName: "Democracy", itemName: "ReferendumInfoFor") + } + + static var votingOf: StorageCodingPath { + StorageCodingPath(moduleName: "Democracy", itemName: "VotingOf") + } +} diff --git a/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift b/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift new file mode 100644 index 0000000000..4a4093f137 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift @@ -0,0 +1,11 @@ +import Foundation + +extension Democracy { + static var votingPeriod: ConstantCodingPath { + ConstantCodingPath(moduleName: "Democracy", constantName: "VotingPeriod") + } + + static var enactmentPeriod: ConstantCodingPath { + ConstantCodingPath(moduleName: "Democracy", constantName: "EnactmentPeriod") + } +} diff --git a/novawallet/Common/Substrate/Types/Democracy/Democracy.swift b/novawallet/Common/Substrate/Types/Democracy/Democracy.swift new file mode 100644 index 0000000000..43c41e59fb --- /dev/null +++ b/novawallet/Common/Substrate/Types/Democracy/Democracy.swift @@ -0,0 +1,3 @@ +import Foundation + +enum Democracy {} diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift new file mode 100644 index 0000000000..c879704ec8 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift @@ -0,0 +1,56 @@ +import Foundation +import SubstrateSdk +import BigInt + +extension Democracy { + struct Tally: Decodable { + /// The number of aye votes, expressed in terms of post-conviction lock-vote. + @StringCodable var ayes: BigUInt + + /// The number of nay votes, expressed in terms of post-conviction lock-vote. + @StringCodable var nays: BigUInt + + /// The amount of funds currently expressing its opinion. Pre-conviction. + @StringCodable var turnout: BigUInt + } + + struct OngoingStatus: Decodable { + @StringCodable var end: BlockNumber + @StringCodable var delay: BlockNumber + let threshold: Democracy.VoteThreshold + let tally: Tally + } + + struct FinishedStatus: Decodable { + enum CodingKeys: String, CodingKey { + case approved = "0" + case end = "1" + } + + let approved: Bool + @StringCodable var end: BlockNumber + } + + enum ReferendumInfo: Decodable { + case ongoing(OngoingStatus) + case finished(FinishedStatus) + case unknown + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "Ongoing": + let status = try container.decode(OngoingStatus.self) + self = .ongoing(status) + case "Finished": + let status = try container.decode(FinishedStatus.self) + self = .finished(status) + default: + self = .unknown + } + } + } + +} diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyVoteThreshold.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyVoteThreshold.swift new file mode 100644 index 0000000000..a63b1ab5e6 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyVoteThreshold.swift @@ -0,0 +1,32 @@ +import Foundation + +extension Democracy { + enum VoteThreshold: Decodable { + /// A supermajority of approvals is needed to pass this vote. + case superMajorityApprove + + /// A supermajority of rejects is needed to fail this vote. + case superMajorityAgainst + + /// A simple majority of approvals is needed to pass this vote. + case simpleMajority + + case unknown + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "SuperMajorityApprove": + self = .superMajorityApprove + case "superMajorityAgainst": + self = .superMajorityAgainst + case "SimpleMajority": + self = .simpleMajority + default: + self = .unknown + } + } + } +} diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyVoting.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyVoting.swift new file mode 100644 index 0000000000..b7959ec6b6 --- /dev/null +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyVoting.swift @@ -0,0 +1,43 @@ +import Foundation +import SubstrateSdk + +extension Democracy { + enum Voting: Decodable { + case direct(ConvictionVoting.Casting) + case delegating(ConvictionVoting.Delegating) + case unknown + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "Direct": + let voting = try container.decode(ConvictionVoting.Casting.self) + self = .direct(voting) + case "Delegating": + let voting = try container.decode(ConvictionVoting.Delegating.self) + self = .delegating(voting) + default: + self = .unknown + } + } + } + + struct VotingOfKey: JSONListConvertible, Hashable { + let accountId: AccountId + + init(jsonList: [JSON], context: [CodingUserInfoKey: Any]?) throws { + let expectedFieldsCount = 1 + let actualFieldsCount = jsonList.count + guard expectedFieldsCount == actualFieldsCount else { + throw JSONListConvertibleError.unexpectedNumberOfItems( + expected: expectedFieldsCount, + actual: actualFieldsCount + ) + } + + accountId = try jsonList[0].map(to: AccountId.self, with: context) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift b/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift new file mode 100644 index 0000000000..c4ab4bfc2e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift @@ -0,0 +1,96 @@ +import Foundation +import BigInt + +protocol DemocracyDecidingFunctionProtocol { + var thresholdType: Democracy.VoteThreshold { get } + func calculateThreshold( + for ayes: BigUInt, + nays: BigUInt, + turnout: BigUInt, + electorate: BigUInt + ) -> Decimal? +} + +final class Gov1DecidingFunction { + let thresholdType: Democracy.VoteThreshold + + init(thresholdType: Democracy.VoteThreshold) { + self.thresholdType = thresholdType + } + + private func calculateSupermajorityApprove( + for ayes: BigUInt, + nays: BigUInt, + turnout: BigUInt, + electorate: BigUInt + ) -> Decimal? { + guard + let totalDecimal = Decimal(ayes + nays), + let naysDecimal = Decimal(nays), + let turnoutSqrt = Decimal(turnout.squareRoot()), + let electorateSqrt = Decimal(electorate.squareRoot()) else { + return nil + } + + guard totalDecimal > 0, turnoutSqrt > 0 else { + return nil + } + + let naysFraction = naysDecimal / totalDecimal + + return naysFraction * (electorateSqrt / turnoutSqrt) + } + + private func calculateSupermajorityAgainst( + for ayes: BigUInt, + nays: BigUInt, + turnout: BigUInt, + electorate: BigUInt + ) -> Decimal? { + guard + let totalDecimal = Decimal(ayes + nays), + let naysDecimal = Decimal(nays), + let turnoutSqrt = Decimal(turnout.squareRoot()), + let electorateSqrt = Decimal(electorate.squareRoot()) else { + return nil + } + + guard totalDecimal > 0, electorateSqrt > 0 else { + return nil + } + + let naysFraction = naysDecimal / totalDecimal + + return naysFraction * (turnoutSqrt / electorateSqrt) + } +} + +extension Gov1DecidingFunction: DemocracyDecidingFunctionProtocol { + func calculateThreshold( + for ayes: BigUInt, + nays: BigUInt, + turnout: BigUInt, + electorate: BigUInt + ) -> Decimal? { + switch thresholdType { + case .superMajorityApprove: + return calculateSupermajorityApprove( + for: ayes, + nays: nays, + turnout: turnout, + electorate: electorate + ) + case .superMajorityAgainst: + return calculateSupermajorityAgainst( + for: ayes, + nays: nays, + turnout: turnout, + electorate: electorate + ) + case .simpleMajority: + return 0.5 + case .unknown: + return nil + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index bcad25771a..354d2e45e5 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -109,9 +109,39 @@ struct SupportAndVotesLocal { } } +struct VotingThresholdLocal { + let ayes: BigUInt + let nays: BigUInt + let turnout: BigUInt + let electorate: BigUInt + + /// fraction of ayes + var approvalFraction: Decimal? { + guard + let total = Decimal(ayes + nays), total > 0, + let ayesDecimal = Decimal(ayes) else { + return nil + } + + return ayesDecimal / total + } + + let thresholdFunction: DemocracyDecidingFunctionProtocol + + func calculateThreshold() -> Decimal? { + thresholdFunction.calculateThreshold( + for: ayes, + nays: nays, + turnout: turnout, + electorate: electorate + ) + } +} + enum ReferendumStateLocal { enum Voting { - case supportAndVotes(model: SupportAndVotesLocal) + case supportAndVotes(SupportAndVotesLocal) + case threshold(VotingThresholdLocal) } struct Deciding { diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift new file mode 100644 index 0000000000..1ef208b19d --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift @@ -0,0 +1,72 @@ +import Foundation + +final class Gov1LocalMappingFactory { + private func mapOngoing( + referendum: Democracy.OngoingStatus, + index: Referenda.ReferendumIndex, + additionalInfo: Gov1OperationFactory.AdditionalInfo + ) -> ReferendumLocal { + let track = GovernanceTrackLocal(trackId: Gov1OperationFactory.trackId, name: Gov1OperationFactory.trackName) + + let submitted = referendum.end - additionalInfo.votingPeriod + + let voting = VotingThresholdLocal( + ayes: referendum.tally.ayes, + nays: referendum.tally.nays, + turnout: referendum.tally.turnout, + electorate: additionalInfo.totalIssuance, + thresholdFunction: Gov1DecidingFunction(thresholdType: referendum.threshold) + ) + + let state = ReferendumStateLocal.Deciding( + track: track, + proposal: .unknown, + voting: .threshold(voting), + submitted: submitted, + since: submitted, + period: additionalInfo.votingPeriod, + confirmationUntil: nil, + deposit: nil + ) + + return .init(index: ReferendumIdLocal(index), state: .deciding(model: state), proposer: nil) + } + + private func mapFinished( + referendum: Democracy.FinishedStatus, + index: Referenda.ReferendumIndex, + additionalInfo: Gov1OperationFactory.AdditionalInfo + ) -> ReferendumLocal { + if referendum.approved { + let approved = ReferendumStateLocal.Approved( + since: referendum.end, + whenEnactment: referendum.end + additionalInfo.enactmentPeriod, + deposit: nil + ) + return .init(index: ReferendumIdLocal(index), state: .approved(model: approved), proposer: nil) + } else { + let rejected = ReferendumStateLocal.NotApproved( + atBlock: referendum.end, + deposit: nil + ) + return .init(index: ReferendumIdLocal(index), state: .rejected(model: rejected), proposer: nil) + } + } +} + +extension Gov1LocalMappingFactory { + func mapRemote( + referendum: Democracy.ReferendumInfo, + index: Referenda.ReferendumIndex, + additionalInfo: Gov1OperationFactory.AdditionalInfo + ) -> ReferendumLocal? { + switch referendum { + case let .ongoing(status): + return mapOngoing(referendum: status, index: index, additionalInfo: additionalInfo) + case let .finished(status): + return mapFinished(referendum: status, index: index, additionalInfo: additionalInfo) + case .unknown: + return nil + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift new file mode 100644 index 0000000000..f5bb8bfb2c --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift @@ -0,0 +1,198 @@ +import Foundation +import RobinHood +import BigInt +import SubstrateSdk + +extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { + func fetchAllReferendumsWrapper( + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[ReferendumLocal]> { + let request = UnkeyedRemoteStorageRequest(storagePath: Democracy.referendumInfo) + + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let referendumWrapper: CompoundOperationWrapper<[ReferendumIndexKey: Democracy.ReferendumInfo]> = + requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: request.storagePath, + factory: { try codingFactoryOperation.extractNoCancellableResultData() } + ) + + referendumWrapper.addDependency(operations: [codingFactoryOperation]) + + let additionalWrapper = createAdditionalInfoWrapper( + dependingOn: codingFactoryOperation, + connection: connection, + blockHash: nil + ) + + additionalWrapper.addDependency(operations: [codingFactoryOperation]) + + let mapOperation = createReferendumMapOperation( + dependingOn: referendumWrapper.targetOperation, + additionalInfoOperation: additionalWrapper.targetOperation + ) + + mapOperation.addDependency(additionalWrapper.targetOperation) + mapOperation.addDependency(referendumWrapper.targetOperation) + + return .init( + targetOperation: mapOperation, + dependencies: [codingFactoryOperation] + referendumWrapper.allOperations + additionalWrapper.allOperations + ) + } + + func fetchReferendumWrapper( + for remoteReferendum: Democracy.ReferendumInfo, + index: ReferendumIdLocal, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let additionalInfoWrapper = createAdditionalInfoWrapper( + dependingOn: codingFactoryOperation, + connection: connection, + blockHash: blockHash + ) + + let referendumOperation = ClosureOperation<[ReferendumIndexKey: Democracy.ReferendumInfo]> { + let referendumIndexKey = ReferendumIndexKey(referendumIndex: Referenda.ReferendumIndex(index)) + return [referendumIndexKey: remoteReferendum] + } + + let mergeOperation = createReferendumMapOperation( + dependingOn: referendumOperation, + additionalInfoOperation: additionalInfoWrapper.targetOperation + ) + + mergeOperation.addDependency(referendumOperation) + mergeOperation.addDependency(additionalInfoWrapper.targetOperation) + + let mapOperation = ClosureOperation { + guard let referendum = try mergeOperation.extractNoCancellableResultData().first else { + throw BaseOperationError.unexpectedDependentResult + } + + return referendum + } + + mapOperation.addDependency(mergeOperation) + + let dependencies = [codingFactoryOperation, referendumOperation] + + additionalInfoWrapper.allOperations + [mergeOperation] + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } + + func fetchAccountVotesWrapper( + for accountId: AccountId, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let keyParams: () throws -> [BytesCodable] = { + [BytesCodable(wrappedValue: accountId)] + } + + let votesWrapper: CompoundOperationWrapper<[StorageResponse]> = + requestFactory.queryItems( + engine: connection, + keyParams: keyParams, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: Democracy.votingOf, + at: blockHash + ) + + votesWrapper.addDependency(operations: [codingFactoryOperation]) + + let maxVotesOperation = createMaxVotesOperation(dependingOn: codingFactoryOperation) + maxVotesOperation.addDependency(codingFactoryOperation) + + let mappingOperation = ClosureOperation { + let optVoting = try votesWrapper.targetOperation.extractNoCancellableResultData().first?.value + let maxVotes = try maxVotesOperation.extractNoCancellableResultData() + + let initVotingLocal = ReferendumAccountVotingDistribution(maxVotesPerTrack: maxVotes) + + if let voting = optVoting { + let track = TrackIdLocal(Gov1OperationFactory.trackId) + switch voting { + case let .direct(castingVoting): + return castingVoting.votes.reduce(initVotingLocal) { result, vote in + let newResult = result.addingReferendum(ReferendumIdLocal(vote.pollIndex), track: track) + + guard let localVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { + return newResult + } + + return newResult.addingVote(localVote, referendumId: ReferendumIdLocal(vote.pollIndex)) + }.addingPriorLock(castingVoting.prior, track: track) + case let .delegating(delegatingVoting): + let delegatingLocal = ReferendumDelegatingLocal(remote: delegatingVoting) + return initVotingLocal.addingDelegating(delegatingLocal, trackId: track) + case .unknown: + return initVotingLocal + } + } else { + return initVotingLocal + } + } + + mappingOperation.addDependency(votesWrapper.targetOperation) + mappingOperation.addDependency(maxVotesOperation) + + let dependencies = [codingFactoryOperation, maxVotesOperation] + votesWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } + + func fetchVotersWrapper(for referendumIndex: ReferendumIdLocal, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol) -> CompoundOperationWrapper<[ReferendumVoterLocal]> { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let request = UnkeyedRemoteStorageRequest(storagePath: Democracy.votingOf) + + let votesWrapper: CompoundOperationWrapper<[Democracy.VotingOfKey: Democracy.Voting]> = + requestFactory.queryByPrefix( + engine: connection, + request: request, + storagePath: Democracy.votingOf, + factory: { try codingFactoryOperation.extractNoCancellableResultData() } + ) + + votesWrapper.addDependency(operations: [codingFactoryOperation]) + + let mappingOperation = ClosureOperation<[ReferendumVoterLocal]> { + let votesResult = try votesWrapper.targetOperation.extractNoCancellableResultData() + + return votesResult.compactMap { keyValue in + let accountId = keyValue.key.accountId + let voting = keyValue.value + + switch voting { + case let .direct(directVoting): + guard + let vote = directVoting.votes.first(where: { $0.pollIndex == referendumIndex }), + let accountVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { + return nil + } + + return ReferendumVoterLocal(accountId: accountId, vote: accountVote) + case .delegating, .unknown: + return nil + } + } + } + + mappingOperation.addDependency(votesWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + votesWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift index 2b9358e7fa..eec4e3b40b 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift @@ -4,21 +4,108 @@ import BigInt import SubstrateSdk final class Gov1OperationFactory { + static let trackName: String = "root" + static let trackId: Referenda.TrackId = 0 -} + struct AdditionalInfo { + let votingPeriod: UInt32 + let enactmentPeriod: UInt32 + let totalIssuance: BigUInt + } -extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { - func fetchAllReferendumsWrapper(from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol) -> CompoundOperationWrapper<[ReferendumLocal]> { - <#code#> + let requestFactory: StorageRequestFactoryProtocol + let operationQueue: OperationQueue + + init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { + self.requestFactory = requestFactory + self.operationQueue = operationQueue } - func fetchAccountVotesWrapper(for accountId: AccountId, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockHash: Data?) -> CompoundOperationWrapper { - <#code#> + func createAdditionalInfoWrapper( + dependingOn codingFactoryOperation: BaseOperation, + connection: JSONRPCEngine, + blockHash: Data? + ) -> CompoundOperationWrapper { + let votingPeriodOperation = PrimitiveConstantOperation(path: Democracy.votingPeriod) + votingPeriodOperation.configurationBlock = { + do { + votingPeriodOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + votingPeriodOperation.result = .failure(error) + } + } + + let enactmentPeriodOperation = PrimitiveConstantOperation(path: Democracy.enactmentPeriod) + enactmentPeriodOperation.configurationBlock = { + do { + enactmentPeriodOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + enactmentPeriodOperation.result = .failure(error) + } + } + + let totalIssuanceWrapper: CompoundOperationWrapper>> = + requestFactory.queryItem( + engine: connection, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: .totalIssuance, + at: blockHash + ) + + let mapOperation = ClosureOperation { + let votingPeriod = try votingPeriodOperation.extractNoCancellableResultData() + let totalIssuance = try totalIssuanceWrapper.targetOperation.extractNoCancellableResultData().value + let enactmentPeriod = try enactmentPeriodOperation.extractNoCancellableResultData() + + return .init( + votingPeriod: votingPeriod, + enactmentPeriod: enactmentPeriod, + totalIssuance: totalIssuance?.value ?? 0 + ) + } + + mapOperation.addDependency(votingPeriodOperation) + mapOperation.addDependency(totalIssuanceWrapper.targetOperation) + mapOperation.addDependency(enactmentPeriodOperation) + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: [votingPeriodOperation]) } - func fetchVotersWrapper(for referendumIndex: ReferendumIdLocal, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol) -> CompoundOperationWrapper<[ReferendumVoterLocal]> { - <#code#> + func createReferendumMapOperation( + dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: Democracy.ReferendumInfo]>, + additionalInfoOperation: BaseOperation + ) -> BaseOperation<[ReferendumLocal]> { + ClosureOperation<[ReferendumLocal]> { + let remoteReferendums = try referendumOperation.extractNoCancellableResultData() + let additionalInfo = try additionalInfoOperation.extractNoCancellableResultData() + + let mappingFactory = Gov1LocalMappingFactory() + + return remoteReferendums.compactMap { keyedReferendum in + let referendumIndex = ReferendumIdLocal(keyedReferendum.key.referendumIndex) + let remoteReferendum = keyedReferendum.value + + return mappingFactory.mapRemote( + referendum: remoteReferendum, + index: Referenda.ReferendumIndex(referendumIndex), + additionalInfo: additionalInfo + ) + } + } } + func createMaxVotesOperation( + dependingOn codingFactoryOperation: BaseOperation + ) -> BaseOperation { + let maxVotesOperation = PrimitiveConstantOperation(path: ConvictionVoting.maxVotes) + maxVotesOperation.configurationBlock = { + do { + maxVotesOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + maxVotesOperation.result = .failure(error) + } + } + return maxVotesOperation + } } From 18b1de588259c11dda7bd2090645e182485ee1a8 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 6 Nov 2022 23:36:54 +0500 Subject: [PATCH 157/229] add gov1 subscription --- novawallet.xcodeproj/project.pbxproj | 4 + .../Democracy/Democracy+ConstantPath.swift | 4 + .../Types/Democracy/DemocracyReferendum.swift | 1 - .../Governance/Model/ReferendumLocal.swift | 17 + .../Operation/Gov1LocalMappingFactory.swift | 44 +++ .../Gov1OperationFactory+Protocol.swift | 61 ++-- .../Operation/Gov1OperationFactory.swift | 2 +- .../Operation/Gov2LocalMappingFactory.swift | 4 +- .../ReferendumStateLocal+Presenter.swift | 4 + .../Gov1SubscriptionFactory.swift | 298 ++++++++++++++++++ .../ReferendumDisplayStringFactory.swift | 3 + .../ReferendumStatusViewModelFactory.swift | 40 ++- .../ReferendumTimelineViewModelFactory.swift | 36 ++- 13 files changed, 445 insertions(+), 73 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index e36e233400..03092a856c 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -961,6 +961,7 @@ 845B07F729162AB3005785D3 /* Democracy+ConstantPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07F629162AB3005785D3 /* Democracy+ConstantPath.swift */; }; 845B07F929162D24005785D3 /* Gov1LocalMappingFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */; }; 845B07FD291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */; }; + 845B07FF2916F529005785D3 /* Gov1SubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07FE2916F529005785D3 /* Gov1SubscriptionFactory.swift */; }; 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811128F429BB0040CE84 /* SupportPallet.swift */; }; 845B811528F43C350040CE84 /* Treasury.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811428F43C350040CE84 /* Treasury.swift */; }; 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811628F43C730040CE84 /* TreasuryProposal.swift */; }; @@ -3924,6 +3925,7 @@ 845B07F629162AB3005785D3 /* Democracy+ConstantPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Democracy+ConstantPath.swift"; sourceTree = ""; }; 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1LocalMappingFactory.swift; sourceTree = ""; }; 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemocracyDecidingFunctionProtocol.swift; sourceTree = ""; }; + 845B07FE2916F529005785D3 /* Gov1SubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1SubscriptionFactory.swift; sourceTree = ""; }; 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; @@ -8056,6 +8058,7 @@ children = ( 8453DE5428FD24FF0055345C /* GovernanceSubscriptionProtocol.swift */, 8453DE5628FD27390055345C /* Gov2SubscriptionFactory.swift */, + 845B07FE2916F529005785D3 /* Gov1SubscriptionFactory.swift */, ); path = Subscription; sourceTree = ""; @@ -14894,6 +14897,7 @@ F471897626C297AA006487AD /* AnalyticsValidatorsPage.swift in Sources */, F44CD8F426242825005DDF23 /* PayoutRewardsService+Fetch.swift in Sources */, 2AD0A19525D3D3EC00312428 /* GitHubOperationFactory.swift in Sources */, + 845B07FF2916F529005785D3 /* Gov1SubscriptionFactory.swift in Sources */, 888A3B6528F73DC300E15BD2 /* ReferendumVotingStatusView.swift in Sources */, 843E9B3627C8B915009C143A /* NftFileDownloadService.swift in Sources */, 842B17FF28649CCD0014CC57 /* CrossChainDestinationSelectionState.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift b/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift index 4a4093f137..e58e200094 100644 --- a/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift +++ b/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift @@ -8,4 +8,8 @@ extension Democracy { static var enactmentPeriod: ConstantCodingPath { ConstantCodingPath(moduleName: "Democracy", constantName: "EnactmentPeriod") } + + static var maxVotes: ConstantCodingPath { + ConstantCodingPath(moduleName: "Democracy", constantName: "MaxVotes") + } } diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift index c879704ec8..505a61dc3c 100644 --- a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift @@ -52,5 +52,4 @@ extension Democracy { } } } - } diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 354d2e45e5..ebd3ce1be0 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -136,6 +136,14 @@ struct VotingThresholdLocal { electorate: electorate ) } + + func isPassing() -> Bool { + if let threshold = calculateThreshold(), let approvalFraction = approvalFraction { + return approvalFraction > threshold + } else { + return false + } + } } enum ReferendumStateLocal { @@ -157,6 +165,15 @@ enum ReferendumStateLocal { var rejectedAt: BlockNumber { since + period } + + func isPassing(for currentBlock: BlockNumber) -> Bool { + switch voting { + case let .supportAndVotes(model): + return model.isPassing(at: currentBlock) + case let .threshold(model): + return model.isPassing() + } + } } struct InQueuePosition { diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift index 1ef208b19d..05164112d4 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift @@ -52,6 +52,36 @@ final class Gov1LocalMappingFactory { return .init(index: ReferendumIdLocal(index), state: .rejected(model: rejected), proposer: nil) } } + + private func mapToAccountVoting( + _ voting: Democracy.Voting?, + maxVotes: UInt32 + ) -> ReferendumAccountVotingDistribution { + let initVotingLocal = ReferendumAccountVotingDistribution(maxVotesPerTrack: maxVotes) + + if let voting = voting { + let track = TrackIdLocal(Gov1OperationFactory.trackId) + switch voting { + case let .direct(castingVoting): + return castingVoting.votes.reduce(initVotingLocal) { result, vote in + let newResult = result.addingReferendum(ReferendumIdLocal(vote.pollIndex), track: track) + + guard let localVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { + return newResult + } + + return newResult.addingVote(localVote, referendumId: ReferendumIdLocal(vote.pollIndex)) + }.addingPriorLock(castingVoting.prior, track: track) + case let .delegating(delegatingVoting): + let delegatingLocal = ReferendumDelegatingLocal(remote: delegatingVoting) + return initVotingLocal.addingDelegating(delegatingLocal, trackId: track) + case .unknown: + return initVotingLocal + } + } else { + return initVotingLocal + } + } } extension Gov1LocalMappingFactory { @@ -69,4 +99,18 @@ extension Gov1LocalMappingFactory { return nil } } + + func mapVoting(_ voting: Democracy.Voting?, maxVotes: UInt32) -> ReferendumTracksVotingDistribution { + let accountVoting = mapToAccountVoting(voting, maxVotes: maxVotes) + + let trackId = Gov1OperationFactory.trackId + let lockedBalance = accountVoting.lockedBalance(for: TrackIdLocal(trackId)) + + if lockedBalance > 0 { + let trackLock = ConvictionVoting.ClassLock(trackId: trackId, amount: lockedBalance) + return .init(votes: accountVoting, trackLocks: [trackLock]) + } else { + return .init(votes: accountVoting, trackLocks: []) + } + } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift index f5bb8bfb2c..4d58b44598 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift @@ -88,6 +88,28 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } + func fetchTracksVotingWrapper( + for voting: Democracy.Voting?, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let maxVotesOperation = createMaxVotesOperation(dependingOn: codingFactoryOperation) + maxVotesOperation.addDependency(codingFactoryOperation) + + let mappingOperation = ClosureOperation { + let maxVotes = try maxVotesOperation.extractNoCancellableResultData() + + return Gov1LocalMappingFactory().mapVoting(voting, maxVotes: maxVotes) + } + + mappingOperation.addDependency(maxVotesOperation) + + let dependencies = [codingFactoryOperation, maxVotesOperation] + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } + func fetchAccountVotesWrapper( for accountId: AccountId, from connection: JSONRPCEngine, @@ -101,13 +123,13 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { } let votesWrapper: CompoundOperationWrapper<[StorageResponse]> = - requestFactory.queryItems( - engine: connection, - keyParams: keyParams, - factory: { try codingFactoryOperation.extractNoCancellableResultData() }, - storagePath: Democracy.votingOf, - at: blockHash - ) + requestFactory.queryItems( + engine: connection, + keyParams: keyParams, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: Democracy.votingOf, + at: blockHash + ) votesWrapper.addDependency(operations: [codingFactoryOperation]) @@ -118,30 +140,7 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { let optVoting = try votesWrapper.targetOperation.extractNoCancellableResultData().first?.value let maxVotes = try maxVotesOperation.extractNoCancellableResultData() - let initVotingLocal = ReferendumAccountVotingDistribution(maxVotesPerTrack: maxVotes) - - if let voting = optVoting { - let track = TrackIdLocal(Gov1OperationFactory.trackId) - switch voting { - case let .direct(castingVoting): - return castingVoting.votes.reduce(initVotingLocal) { result, vote in - let newResult = result.addingReferendum(ReferendumIdLocal(vote.pollIndex), track: track) - - guard let localVote = ReferendumAccountVoteLocal(accountVote: vote.accountVote) else { - return newResult - } - - return newResult.addingVote(localVote, referendumId: ReferendumIdLocal(vote.pollIndex)) - }.addingPriorLock(castingVoting.prior, track: track) - case let .delegating(delegatingVoting): - let delegatingLocal = ReferendumDelegatingLocal(remote: delegatingVoting) - return initVotingLocal.addingDelegating(delegatingLocal, trackId: track) - case .unknown: - return initVotingLocal - } - } else { - return initVotingLocal - } + return Gov1LocalMappingFactory().mapVoting(optVoting, maxVotes: maxVotes).votes } mappingOperation.addDependency(votesWrapper.targetOperation) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift index eec4e3b40b..5e7a2c2741 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift @@ -97,7 +97,7 @@ final class Gov1OperationFactory { func createMaxVotesOperation( dependingOn codingFactoryOperation: BaseOperation ) -> BaseOperation { - let maxVotesOperation = PrimitiveConstantOperation(path: ConvictionVoting.maxVotes) + let maxVotesOperation = PrimitiveConstantOperation(path: Democracy.maxVotes) maxVotesOperation.configurationBlock = { do { maxVotesOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index 5cd873dccb..9dbb261f9e 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -36,7 +36,7 @@ final class Gov2LocalMappingFactory { let model = ReferendumStateLocal.Deciding( track: localTrack, proposal: status.proposal, - voting: .supportAndVotes(model: votes), + voting: .supportAndVotes(votes), submitted: status.submitted, since: deciding.since, period: track.decisionPeriod, @@ -91,7 +91,7 @@ final class Gov2LocalMappingFactory { let preparing = ReferendumStateLocal.Preparing( track: localTrack, proposal: status.proposal, - voting: .supportAndVotes(model: votes), + voting: .supportAndVotes(votes), deposit: status.decisionDeposit?.amount, since: status.submitted, preparingPeriod: track.preparePeriod, diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift index 6398b09bd7..7702b566c3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift @@ -5,6 +5,8 @@ extension ReferendumStateLocal { switch voting { case let .supportAndVotes(model): return model.approvalFunction?.curve + case .threshold: + return nil case .none: return nil } @@ -14,6 +16,8 @@ extension ReferendumStateLocal { switch voting { case let .supportAndVotes(model): return model.supportFunction?.curve + case .threshold: + return nil case .none: return nil } diff --git a/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift b/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift new file mode 100644 index 0000000000..4f7923585a --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift @@ -0,0 +1,298 @@ +import Foundation +import SubstrateSdk +import RobinHood + +final class Gov1SubscriptionFactory: AnyCancellableCleaning { + typealias ReferendumState = NotEqualWrapper + typealias VotesState = NotEqualWrapper + typealias VotesWrapper = StorageSubscriptionObserver + + typealias ReferendumWrapper = StorageSubscriptionObserver< + Democracy.ReferendumInfo, ReferendumState + > + + private(set) var referendums: [ReferendumIdLocal: ReferendumWrapper] = [:] + private(set) var votes: [AccountId: VotesWrapper] = [:] + private(set) var cancellables: [String: CancellableCall] = [:] + + let operationFactory: Gov1OperationFactory + let chainRegistry: ChainRegistryProtocol + let operationQueue: OperationQueue + let chainId: ChainModel.Id + + init( + chainId: ChainModel.Id, + operationFactory: Gov1OperationFactory, + chainRegistry: ChainRegistryProtocol, + operationQueue: OperationQueue + ) { + self.chainId = chainId + self.operationFactory = operationFactory + self.chainRegistry = chainRegistry + self.operationQueue = operationQueue + } + + private func handleReferendumResult( + _ result: Result, Error>, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + referendumIndex: ReferendumIdLocal + ) { + guard let wrapper = referendums[referendumIndex] else { + return + } + + switch result { + case let .success(result): + if let referendumInfo = result.value { + handleReferendum( + for: referendumInfo, + connection: connection, + runtimeProvider: runtimeProvider, + referendumIndex: referendumIndex, + blockHash: result.blockHash + ) + } else { + let value = CallbackStorageSubscriptionResult(value: nil, blockHash: nil) + wrapper.state = NotEqualWrapper(value: .success(value)) + } + case let .failure(error): + wrapper.state = NotEqualWrapper(value: .failure(error)) + } + } + + private func handleReferendum( + for referendumInfo: Democracy.ReferendumInfo, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + referendumIndex: ReferendumIdLocal, + blockHash: Data? + ) { + let cancellableKey = "referendum-\(referendumIndex)" + clear(cancellable: &cancellables[cancellableKey]) + + let wrapper = operationFactory.fetchReferendumWrapper( + for: referendumInfo, + index: referendumIndex, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.cancellables[cancellableKey] else { + return + } + + self?.cancellables[cancellableKey] = nil + + do { + let referendum = try wrapper.targetOperation.extractNoCancellableResultData() + let value = CallbackStorageSubscriptionResult( + value: referendum, + blockHash: blockHash + ) + + self?.referendums[referendumIndex]?.state = NotEqualWrapper(value: .success(value)) + } catch { + self?.referendums[referendumIndex]?.state = NotEqualWrapper(value: .failure(error)) + } + } + } + + cancellables[cancellableKey] = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } + + private func handleVotesResult( + _ result: Result, Error>, + runtimeProvider: RuntimeProviderProtocol, + accountId: AccountId + ) { + guard let wrapper = votes[accountId] else { + return + } + + switch result { + case let .success(result): + handleVotes( + for: result.value, + runtimeProvider: runtimeProvider, + accountId: accountId, + blockHash: result.blockHash + ) + case let .failure(error): + wrapper.state = NotEqualWrapper(value: .failure(error)) + } + } + + private func handleVotes( + for votes: Democracy.Voting?, + runtimeProvider: RuntimeProviderProtocol, + accountId: AccountId, + blockHash: Data? + ) { + let cancellableKey = "votes-\(accountId.toHex())" + clear(cancellable: &cancellables[cancellableKey]) + + let wrapper = operationFactory.fetchTracksVotingWrapper( + for: votes, + runtimeProvider: runtimeProvider + ) + + wrapper.targetOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard wrapper === self?.cancellables[cancellableKey] else { + return + } + + self?.cancellables[cancellableKey] = nil + + do { + let tracksVoting = try wrapper.targetOperation.extractNoCancellableResultData() + let value = CallbackStorageSubscriptionResult( + value: tracksVoting, + blockHash: blockHash + ) + + self?.votes[accountId]?.state = NotEqualWrapper(value: .success(value)) + } catch { + self?.votes[accountId]?.state = NotEqualWrapper(value: .failure(error)) + } + } + } + + cancellables[cancellableKey] = wrapper + + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + } +} + +extension Gov1SubscriptionFactory: GovernanceSubscriptionFactoryProtocol { + func subscribeToReferendum( + _ target: AnyObject, + referendumIndex: UInt, + notificationClosure: @escaping (ReferendumSubscriptionResult?) -> Void + ) { + let subscriptionWrapper: ReferendumWrapper + + if let wrapper = referendums[referendumIndex] { + subscriptionWrapper = wrapper + } else { + let request = MapSubscriptionRequest(storagePath: Democracy.referendumInfo, localKey: "") { + StringScaleMapper(value: referendumIndex) + } + + guard let connection = chainRegistry.getConnection(for: chainId) else { + notificationClosure(.failure(ChainRegistryError.connectionUnavailable)) + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + notificationClosure(.failure(ChainRegistryError.runtimeMetadaUnavailable)) + return + } + + let subscription = CallbackStorageSubscription( + request: request, + connection: connection, + runtimeService: runtimeProvider, + repository: nil, + operationQueue: operationQueue, + callbackWithBlockQueue: .main + ) { [weak self] result in + self?.handleReferendumResult( + result, + connection: connection, + runtimeProvider: runtimeProvider, + referendumIndex: referendumIndex + ) + } + + subscriptionWrapper = ReferendumWrapper(subscription: subscription) + referendums[referendumIndex] = subscriptionWrapper + } + + notificationClosure(subscriptionWrapper.state?.value) + + subscriptionWrapper.addObserver(with: target) { _, newValueWrapper in + notificationClosure(newValueWrapper?.value) + } + } + + func unsubscribeFromReferendum(_: AnyObject, referendumIndex: ReferendumIdLocal) { + guard let subscriptionWrapper = referendums[referendumIndex] else { + return + } + + subscriptionWrapper.removeObserver(by: self) + + if subscriptionWrapper.observers.isEmpty { + referendums[referendumIndex] = nil + } + } + + func subscribeToAccountVotes( + _ target: AnyObject, + accountId: AccountId, + notificationClosure: @escaping (ReferendumVotesSubscriptionResult?) -> Void + ) { + let subscriptionWrapper: VotesWrapper + + if let wrapper = votes[accountId] { + subscriptionWrapper = wrapper + } else { + let request = MapSubscriptionRequest(storagePath: Democracy.votingOf, localKey: "") { + BytesCodable(wrappedValue: accountId) + } + + guard let connection = chainRegistry.getConnection(for: chainId) else { + notificationClosure(.failure(ChainRegistryError.connectionUnavailable)) + return + } + + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + notificationClosure(.failure(ChainRegistryError.runtimeMetadaUnavailable)) + return + } + + let subscription = CallbackStorageSubscription( + request: request, + connection: connection, + runtimeService: runtimeProvider, + repository: nil, + operationQueue: operationQueue, + callbackWithBlockQueue: .main + ) { [weak self] result in + self?.handleVotesResult( + result, + runtimeProvider: runtimeProvider, + accountId: accountId + ) + } + + subscriptionWrapper = VotesWrapper(subscription: subscription) + votes[accountId] = subscriptionWrapper + } + + notificationClosure(subscriptionWrapper.state?.value) + + subscriptionWrapper.addObserver(with: target) { _, newValueWrapper in + notificationClosure(newValueWrapper?.value) + } + } + + func unsubscribeFromAccountVotes(_: AnyObject, accountId: AccountId) { + guard let subscriptionWrapper = votes[accountId] else { + return + } + + subscriptionWrapper.removeObserver(by: self) + + if subscriptionWrapper.observers.isEmpty { + votes[accountId] = nil + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift index ed1a6c1106..7fea807594 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumDisplayStringFactory.swift @@ -29,6 +29,9 @@ extension ReferendumDisplayStringFactoryProtocol { case let .supportAndVotes(model): ayesString = createVotes(from: model.ayes, chain: chain, locale: locale) naysString = createVotes(from: model.nays, chain: chain, locale: locale) + case let .threshold(model): + ayesString = createVotes(from: model.ayes, chain: chain, locale: locale) + naysString = createVotes(from: model.nays, chain: chain, locale: locale) } let aye: VoteRowView.Model? = ayesString.map { diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift index b21adb8cae..7c8335ed02 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumStatusViewModelFactory.swift @@ -133,28 +133,24 @@ extension ReferendumStatusViewModelFactory: ReferendumStatusViewModelFactoryProt ) } case let .deciding(model): - switch model.voting { - case let .supportAndVotes(supportAndVotes): - if supportAndVotes.isPassing(at: currentBlock), - let confirmationUntil = model.confirmationUntil { - return createTimeViewModel( - state: referendum.state, - atBlock: confirmationUntil, - currentBlock: currentBlock, - blockDuration: blockDuration, - timeStringProvider: strings.governanceReferendumsTimeApprove, - locale: locale - ) - } else { - return createTimeViewModel( - state: referendum.state, - atBlock: model.rejectedAt, - currentBlock: currentBlock, - blockDuration: blockDuration, - timeStringProvider: strings.governanceReferendumsTimeReject, - locale: locale - ) - } + if model.isPassing(for: currentBlock), let confirmationUntil = model.confirmationUntil { + return createTimeViewModel( + state: referendum.state, + atBlock: confirmationUntil, + currentBlock: currentBlock, + blockDuration: blockDuration, + timeStringProvider: strings.governanceReferendumsTimeApprove, + locale: locale + ) + } else { + return createTimeViewModel( + state: referendum.state, + atBlock: model.rejectedAt, + currentBlock: currentBlock, + blockDuration: blockDuration, + timeStringProvider: strings.governanceReferendumsTimeReject, + locale: locale + ) } case let .approved(model): guard let whenEnactment = model.whenEnactment else { diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift index 0351a9bcfe..a067dfc395 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift @@ -116,26 +116,30 @@ final class ReferendumTimelineViewModelFactory { locale: locale ) + let isPassing: Bool switch model.voting { case let .supportAndVotes(votingModel): - let isPassing = votingModel.isPassing(at: currentBlock) - let votingTitle = isPassing ? - R.string.localizable.governanceReferendumsStatusPassing(preferredLanguages: locale.rLanguages) : - R.string.localizable.governanceReferendumsStatusNotPassing(preferredLanguages: locale.rLanguages) - - let title = R.string.localizable.govTimelineVotingFormat( - votingTitle.lowercased().firstLetterCapitalized(), - preferredLanguages: locale.rLanguages - ) + isPassing = votingModel.isPassing(at: currentBlock) + case let .threshold(votingModel): + isPassing = votingModel.isPassing() + } - let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel) } + let votingTitle = isPassing ? + R.string.localizable.governanceReferendumsStatusPassing(preferredLanguages: locale.rLanguages) : + R.string.localizable.governanceReferendumsStatusNotPassing(preferredLanguages: locale.rLanguages) - return .init( - title: title, - subtitle: subtitle, - isLast: false - ) - } + let title = R.string.localizable.govTimelineVotingFormat( + votingTitle.lowercased().firstLetterCapitalized(), + preferredLanguages: locale.rLanguages + ) + + let subtitle = status.map { ReferendumTimelineView.StatusSubtitle.interval($0.viewModel) } + + return .init( + title: title, + subtitle: subtitle, + isLast: false + ) } private func createApprovedTitle(for locale: Locale) -> String { From 066bd905a4dd0b277dde45af1397b86a3c6c49d4 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 7 Nov 2022 00:39:41 +0500 Subject: [PATCH 158/229] gov1 preimages base --- novawallet.xcodeproj/project.pbxproj | 12 +- .../Types/Democracy/DemocracyReferendum.swift | 1 + .../Types/Support/SupportPallet.swift | 20 ++ .../Operation/Gov1LocalMappingFactory.swift | 4 +- .../Gov2ActionOperationFactory.swift | 259 ++++-------------- .../GovernanceActionOperationFactory.swift | 188 +++++++++++++ 6 files changed, 267 insertions(+), 217 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Operation/GovernanceActionOperationFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 03092a856c..5ff78648f0 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -962,13 +962,14 @@ 845B07F929162D24005785D3 /* Gov1LocalMappingFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */; }; 845B07FD291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */; }; 845B07FF2916F529005785D3 /* Gov1SubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07FE2916F529005785D3 /* Gov1SubscriptionFactory.swift */; }; + 845B08012918406A005785D3 /* Gov2ActionOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08002918406A005785D3 /* Gov2ActionOperationFactory.swift */; }; 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811128F429BB0040CE84 /* SupportPallet.swift */; }; 845B811528F43C350040CE84 /* Treasury.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811428F43C350040CE84 /* Treasury.swift */; }; 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811628F43C730040CE84 /* TreasuryProposal.swift */; }; 845B811928F43D4C0040CE84 /* Treasury+CodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811828F43D4C0040CE84 /* Treasury+CodingPath.swift */; }; 845B811B28F445E90040CE84 /* Treasury+Calls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811A28F445E90040CE84 /* Treasury+Calls.swift */; }; 845B811D28F44A700040CE84 /* ReferendumActionLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811C28F44A700040CE84 /* ReferendumActionLocal.swift */; }; - 845B811F28F451A40040CE84 /* Gov2ActionOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */; }; + 845B811F28F451A40040CE84 /* GovernanceActionOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811E28F451A40040CE84 /* GovernanceActionOperationFactory.swift */; }; 845B821526EF657700D25C72 /* PersistentValueSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B821426EF657700D25C72 /* PersistentValueSettings.swift */; }; 845B821726EF7FED00D25C72 /* SelectedWalletSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B821626EF7FED00D25C72 /* SelectedWalletSettings.swift */; }; 845B821926EF808D00D25C72 /* MetaAccountMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B821826EF808D00D25C72 /* MetaAccountMapper.swift */; }; @@ -3926,13 +3927,14 @@ 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1LocalMappingFactory.swift; sourceTree = ""; }; 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemocracyDecidingFunctionProtocol.swift; sourceTree = ""; }; 845B07FE2916F529005785D3 /* Gov1SubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1SubscriptionFactory.swift; sourceTree = ""; }; + 845B08002918406A005785D3 /* Gov2ActionOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2ActionOperationFactory.swift; sourceTree = ""; }; 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; 845B811828F43D4C0040CE84 /* Treasury+CodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Treasury+CodingPath.swift"; sourceTree = ""; }; 845B811A28F445E90040CE84 /* Treasury+Calls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Treasury+Calls.swift"; sourceTree = ""; }; 845B811C28F44A700040CE84 /* ReferendumActionLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumActionLocal.swift; sourceTree = ""; }; - 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2ActionOperationFactory.swift; sourceTree = ""; }; + 845B811E28F451A40040CE84 /* GovernanceActionOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceActionOperationFactory.swift; sourceTree = ""; }; 845B821426EF657700D25C72 /* PersistentValueSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentValueSettings.swift; sourceTree = ""; }; 845B821626EF7FED00D25C72 /* SelectedWalletSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedWalletSettings.swift; sourceTree = ""; }; 845B821826EF808D00D25C72 /* MetaAccountMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaAccountMapper.swift; sourceTree = ""; }; @@ -10363,7 +10365,8 @@ 845B07F4291627A3005785D3 /* Gov1OperationFactory+Protocol.swift */, 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */, 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, - 845B811E28F451A40040CE84 /* Gov2ActionOperationFactory.swift */, + 845B811E28F451A40040CE84 /* GovernanceActionOperationFactory.swift */, + 845B08002918406A005785D3 /* Gov2ActionOperationFactory.swift */, 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */, 8425D0EB28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift */, ); @@ -14712,6 +14715,7 @@ 847F2D4627A9DB8E00AFD476 /* MultigradientView.swift in Sources */, 842876A524AE049B00D91AD8 /* SelectableTitleListViewModel.swift in Sources */, 847C96302553426D002D288F /* ExportGenericViewModel.swift in Sources */, + 845B08012918406A005785D3 /* Gov2ActionOperationFactory.swift in Sources */, 84906FEC28AFD23B0049B57D /* LoadableStackActionCell.swift in Sources */, 8487010A2907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift in Sources */, AEF73FB525DBA24300407D41 /* PhishingCheckExecutor.swift in Sources */, @@ -15560,7 +15564,7 @@ 84786DA825F9F58E0089DFF7 /* EraValidatorService+Fetch.swift in Sources */, 84ACEBFF261E6C7C00AAE665 /* WalletHistoryFilterViewLayout.swift in Sources */, 846A835F28B8D94300D92892 /* MessageSheetNoContentView.swift in Sources */, - 845B811F28F451A40040CE84 /* Gov2ActionOperationFactory.swift in Sources */, + 845B811F28F451A40040CE84 /* GovernanceActionOperationFactory.swift in Sources */, 84754CA22513DB8800854599 /* EmptyAccountIcon.swift in Sources */, 8824D424290324260022D778 /* PrettyPrintedJSONOperationFactory.swift in Sources */, AEA0C8C6268131C500F9666F /* InitiatedBondingSelectedValidatorsListWireframe.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift index 505a61dc3c..b61f4ed017 100644 --- a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift @@ -17,6 +17,7 @@ extension Democracy { struct OngoingStatus: Decodable { @StringCodable var end: BlockNumber @StringCodable var delay: BlockNumber + @SupportPallet.HashOrBoundedCallWrapper var proposal: SupportPallet.Bounded> let threshold: Democracy.VoteThreshold let tally: Tally } diff --git a/novawallet/Common/Substrate/Types/Support/SupportPallet.swift b/novawallet/Common/Substrate/Types/Support/SupportPallet.swift index f9fdacae72..a4c266e44b 100644 --- a/novawallet/Common/Substrate/Types/Support/SupportPallet.swift +++ b/novawallet/Common/Substrate/Types/Support/SupportPallet.swift @@ -36,4 +36,24 @@ enum SupportPallet { } } } + + @propertyWrapper + struct HashOrBoundedCallWrapper: Decodable where T: Decodable { + let wrappedValue: Bounded + + init(wrappedValue: Bounded) { + self.wrappedValue = wrappedValue + } + + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + + if let boundedCall = try? container.decode(Bounded.self) { + wrappedValue = boundedCall + } else { + let hash = try container.decode(BytesCodable.self).wrappedValue + wrappedValue = .legacy(hash: hash) + } + } + } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift index 05164112d4..1d7dec78fc 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift @@ -20,12 +20,12 @@ final class Gov1LocalMappingFactory { let state = ReferendumStateLocal.Deciding( track: track, - proposal: .unknown, + proposal: referendum.proposal, voting: .threshold(voting), submitted: submitted, since: submitted, period: additionalInfo.votingPeriod, - confirmationUntil: nil, + confirmationUntil: referendum.end, deposit: nil ) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift index 99a28eabad..2f90b07243 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift @@ -1,246 +1,83 @@ import Foundation -import RobinHood import SubstrateSdk +import RobinHood -final class Gov2ActionOperationFactory { - static let maxFetchCallSize: UInt32 = 1024 - - let requestFactory: StorageRequestFactoryProtocol - let operationQueue: OperationQueue - - init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { - self.requestFactory = requestFactory - self.operationQueue = operationQueue - } - +final class Gov2ActionOperationFactory: GovernanceActionOperationFactory { // swiftlint:disable:next function_body_length - private func createCallFetchWrapper( - dependingOn codingFactoryOperation: BaseOperation, - referendum: ReferendumLocal, - requestFactory: StorageRequestFactoryProtocol, - connection: JSONRPCEngine + override func fetchCall( + for hash: Data, + connection: JSONRPCEngine, + codingFactoryOperation: BaseOperation ) -> CompoundOperationWrapper>?> { - let callFetchClosure: (Data) -> CompoundOperationWrapper>?> - callFetchClosure = { hash in - let statusKeyParams: () throws -> [BytesCodable] = { - [BytesCodable(wrappedValue: hash)] - } - - let statusFetchWrapper: CompoundOperationWrapper<[StorageResponse]> = - requestFactory.queryItems( - engine: connection, - keyParams: statusKeyParams, - factory: { try codingFactoryOperation.extractNoCancellableResultData() }, - storagePath: Preimage.statusForStoragePath - ) - - let callKeyParams: () throws -> [Preimage.PreimageKey] = { - let status = try statusFetchWrapper.targetOperation.extractNoCancellableResultData().first?.value - - guard let length = status?.length, length <= Self.maxFetchCallSize else { - return [] - } - - return [Preimage.PreimageKey(hash: hash, length: length)] - } + let statusKeyParams: () throws -> [BytesCodable] = { + [BytesCodable(wrappedValue: hash)] + } - let callFetchWrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( + let statusFetchWrapper: CompoundOperationWrapper<[StorageResponse]> = + requestFactory.queryItems( engine: connection, - keyParams: callKeyParams, + keyParams: statusKeyParams, factory: { try codingFactoryOperation.extractNoCancellableResultData() }, - storagePath: Preimage.preimageForStoragePath + storagePath: Preimage.statusForStoragePath ) - callFetchWrapper.addDependency(wrapper: statusFetchWrapper) - - let mappingOperation = ClosureOperation>?> { - let callKeys = try callKeyParams() + let callKeyParams: () throws -> [Preimage.PreimageKey] = { + let status = try statusFetchWrapper.targetOperation.extractNoCancellableResultData().first?.value - guard !callKeys.isEmpty else { - let optStatus = try statusFetchWrapper.targetOperation.extractNoCancellableResultData().first?.value + guard let length = status?.length, length <= Self.maxFetchCallSize else { + return [] + } - if let length = optStatus?.length { - return length > Self.maxFetchCallSize ? .tooLong : nil - } else { - return nil - } - } + return [Preimage.PreimageKey(hash: hash, length: length)] + } - let responses = try callFetchWrapper.targetOperation.extractNoCancellableResultData() - guard let response = responses.first?.value else { - return nil - } + let callFetchWrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( + engine: connection, + keyParams: callKeyParams, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: Preimage.preimageForStoragePath + ) - let codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + callFetchWrapper.addDependency(wrapper: statusFetchWrapper) - let decoder = try codingFactory.createDecoder(from: response.wrappedValue) + let mappingOperation = ClosureOperation>?> { + let callKeys = try callKeyParams() - let optCall: RuntimeCall? = try? decoder.read( - of: GenericType.call.name, - with: codingFactory.createRuntimeJsonContext().toRawContext() - ) + guard !callKeys.isEmpty else { + let optStatus = try statusFetchWrapper.targetOperation.extractNoCancellableResultData().first?.value - if let call = optCall { - return .concrete(call) + if let length = optStatus?.length { + return length > Self.maxFetchCallSize ? .tooLong : nil } else { return nil } } - mappingOperation.addDependency(callFetchWrapper.targetOperation) - - let dependencies = statusFetchWrapper.allOperations + callFetchWrapper.allOperations - - return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) - } - - let callDecodingService = OperationCombiningService>?>( - operationManager: OperationManager(operationQueue: operationQueue) - ) { - switch referendum.state.proposal { - case let .legacy(hash): - let wrapper = callFetchClosure(hash) - return [wrapper] - case let .inline(value): - return [CompoundOperationWrapper.createWithResult(.concrete(value))] - case let .lookup(lookup): - if lookup.len <= Self.maxFetchCallSize { - let wrapper = callFetchClosure(lookup.hash) - return [wrapper] - } else { - return [CompoundOperationWrapper.createWithResult(.tooLong)] - } - case .none, .unknown: - return [] - } - } - - let callDecodingOperation = callDecodingService.longrunOperation() - let mappingOperation = ClosureOperation>?> { - try callDecodingOperation.extractNoCancellableResultData().first ?? nil - } - - mappingOperation.addDependency(callDecodingOperation) - - return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: [callDecodingOperation]) - } - - private func createSpendAmountExtractionWrapper( - dependingOn callOperation: BaseOperation>?>, - codingFactoryOperation: BaseOperation, - connection: JSONRPCEngine, - requestFactory: StorageRequestFactoryProtocol - ) -> CompoundOperationWrapper { - let operationManager = OperationManager(operationQueue: operationQueue) - let fetchService = OperationCombiningService( - operationManager: operationManager - ) { - guard let call = try callOperation.extractNoCancellableResultData()?.value else { - return [CompoundOperationWrapper.createWithResult(nil)] + let responses = try callFetchWrapper.targetOperation.extractNoCancellableResultData() + guard let response = responses.first?.value else { + return nil } let codingFactory = try codingFactoryOperation.extractNoCancellableResultData() - let context = codingFactory.createRuntimeJsonContext() - - let codingPath = CallCodingPath(moduleName: call.moduleName, callName: call.callName) - if codingPath == Treasury.spendCallPath { - let spendCall = try call.args.map(to: Treasury.SpendCall.self, with: context.toRawContext()) + let decoder = try codingFactory.createDecoder(from: response.wrappedValue) - let details = ReferendumActionLocal.AmountSpendDetails( - amount: spendCall.amount, - beneficiary: spendCall.beneficiary - ) - - return [CompoundOperationWrapper.createWithResult(details)] - } - - if codingPath == Treasury.approveProposalCallPath { - let approveCall = try call.args.map(to: Treasury.ApproveProposal.self, with: context.toRawContext()) - - let keyClosure: () throws -> [StringScaleMapper] = { - [StringScaleMapper(value: approveCall.proposalId)] - } - - let wrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( - engine: connection, - keyParams: keyClosure, - factory: { codingFactory }, - storagePath: Treasury.proposalsStoragePath - ) - - let mapOperation = ClosureOperation { - let responses = try wrapper.targetOperation.extractNoCancellableResultData() - guard let proposal = responses.first?.value else { - return nil - } - - return ReferendumActionLocal.AmountSpendDetails( - amount: proposal.value, - beneficiary: .accoundId(proposal.beneficiary) - ) - } - - mapOperation.addDependency(wrapper.targetOperation) + let optCall: RuntimeCall? = try? decoder.read( + of: GenericType.call.name, + with: codingFactory.createRuntimeJsonContext().toRawContext() + ) - return [CompoundOperationWrapper(targetOperation: mapOperation, dependencies: wrapper.allOperations)] + if let call = optCall { + return .concrete(call) + } else { + return nil } - - return [CompoundOperationWrapper.createWithResult(nil)] - } - - let fetchOperation = fetchService.longrunOperation() - - let mapOperation = ClosureOperation { - try fetchOperation.extractNoCancellableResultData().first ?? nil - } - - mapOperation.addDependency(fetchOperation) - - return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: [fetchOperation]) - } -} - -extension Gov2ActionOperationFactory: ReferendumActionOperationFactoryProtocol { - func fetchActionWrapper( - for referendum: ReferendumLocal, - connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol - ) -> CompoundOperationWrapper { - let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - - let callFetchWrapper = createCallFetchWrapper( - dependingOn: codingFactoryOperation, - referendum: referendum, - requestFactory: requestFactory, - connection: connection - ) - - callFetchWrapper.addDependency(operations: [codingFactoryOperation]) - - let amountDetailsWrapper = createSpendAmountExtractionWrapper( - dependingOn: callFetchWrapper.targetOperation, - codingFactoryOperation: codingFactoryOperation, - connection: connection, - requestFactory: requestFactory - ) - - amountDetailsWrapper.addDependency(wrapper: callFetchWrapper) - amountDetailsWrapper.addDependency(operations: [codingFactoryOperation]) - - let mapOperation = ClosureOperation { - let call = try callFetchWrapper.targetOperation.extractNoCancellableResultData() - let amountDetails = try amountDetailsWrapper.targetOperation.extractNoCancellableResultData() - - return ReferendumActionLocal(amountSpendDetails: amountDetails, call: call) } - mapOperation.addDependency(callFetchWrapper.targetOperation) - mapOperation.addDependency(amountDetailsWrapper.targetOperation) + mappingOperation.addDependency(callFetchWrapper.targetOperation) - let dependencies = [codingFactoryOperation] + callFetchWrapper.allOperations + - amountDetailsWrapper.allOperations + let dependencies = statusFetchWrapper.allOperations + callFetchWrapper.allOperations - return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) } } diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/GovernanceActionOperationFactory.swift new file mode 100644 index 0000000000..a39714d966 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/GovernanceActionOperationFactory.swift @@ -0,0 +1,188 @@ +import Foundation +import RobinHood +import SubstrateSdk + +class GovernanceActionOperationFactory { + static let maxFetchCallSize: UInt32 = 1024 + + let requestFactory: StorageRequestFactoryProtocol + let operationQueue: OperationQueue + + init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { + self.requestFactory = requestFactory + self.operationQueue = operationQueue + } + + func fetchCall( + for _: Data, + connection _: JSONRPCEngine, + codingFactoryOperation _: BaseOperation + ) -> CompoundOperationWrapper>?> { + fatalError("Must be overriden by child class") + } + + private func createCallFetchWrapper( + dependingOn codingFactoryOperation: BaseOperation, + referendum: ReferendumLocal, + requestFactory _: StorageRequestFactoryProtocol, + connection: JSONRPCEngine + ) -> CompoundOperationWrapper>?> { + let callDecodingService = OperationCombiningService>?>( + operationManager: OperationManager(operationQueue: operationQueue) + ) { + switch referendum.state.proposal { + case let .legacy(hash): + let wrapper = self.fetchCall( + for: hash, + connection: connection, + codingFactoryOperation: codingFactoryOperation + ) + return [wrapper] + case let .inline(value): + return [CompoundOperationWrapper.createWithResult(.concrete(value))] + case let .lookup(lookup): + if lookup.len <= Self.maxFetchCallSize { + let wrapper = self.fetchCall( + for: lookup.hash, + connection: connection, + codingFactoryOperation: codingFactoryOperation + ) + + return [wrapper] + } else { + return [CompoundOperationWrapper.createWithResult(.tooLong)] + } + case .none, .unknown: + return [] + } + } + + let callDecodingOperation = callDecodingService.longrunOperation() + let mappingOperation = ClosureOperation>?> { + try callDecodingOperation.extractNoCancellableResultData().first ?? nil + } + + mappingOperation.addDependency(callDecodingOperation) + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: [callDecodingOperation]) + } + + private func createSpendAmountExtractionWrapper( + dependingOn callOperation: BaseOperation>?>, + codingFactoryOperation: BaseOperation, + connection: JSONRPCEngine, + requestFactory: StorageRequestFactoryProtocol + ) -> CompoundOperationWrapper { + let operationManager = OperationManager(operationQueue: operationQueue) + let fetchService = OperationCombiningService( + operationManager: operationManager + ) { + guard let call = try callOperation.extractNoCancellableResultData()?.value else { + return [CompoundOperationWrapper.createWithResult(nil)] + } + + let codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + let context = codingFactory.createRuntimeJsonContext() + + let codingPath = CallCodingPath(moduleName: call.moduleName, callName: call.callName) + + if codingPath == Treasury.spendCallPath { + let spendCall = try call.args.map(to: Treasury.SpendCall.self, with: context.toRawContext()) + + let details = ReferendumActionLocal.AmountSpendDetails( + amount: spendCall.amount, + beneficiary: spendCall.beneficiary + ) + + return [CompoundOperationWrapper.createWithResult(details)] + } + + if codingPath == Treasury.approveProposalCallPath { + let approveCall = try call.args.map(to: Treasury.ApproveProposal.self, with: context.toRawContext()) + + let keyClosure: () throws -> [StringScaleMapper] = { + [StringScaleMapper(value: approveCall.proposalId)] + } + + let wrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( + engine: connection, + keyParams: keyClosure, + factory: { codingFactory }, + storagePath: Treasury.proposalsStoragePath + ) + + let mapOperation = ClosureOperation { + let responses = try wrapper.targetOperation.extractNoCancellableResultData() + guard let proposal = responses.first?.value else { + return nil + } + + return ReferendumActionLocal.AmountSpendDetails( + amount: proposal.value, + beneficiary: .accoundId(proposal.beneficiary) + ) + } + + mapOperation.addDependency(wrapper.targetOperation) + + return [CompoundOperationWrapper(targetOperation: mapOperation, dependencies: wrapper.allOperations)] + } + + return [CompoundOperationWrapper.createWithResult(nil)] + } + + let fetchOperation = fetchService.longrunOperation() + + let mapOperation = ClosureOperation { + try fetchOperation.extractNoCancellableResultData().first ?? nil + } + + mapOperation.addDependency(fetchOperation) + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: [fetchOperation]) + } +} + +extension GovernanceActionOperationFactory: ReferendumActionOperationFactoryProtocol { + func fetchActionWrapper( + for referendum: ReferendumLocal, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let callFetchWrapper = createCallFetchWrapper( + dependingOn: codingFactoryOperation, + referendum: referendum, + requestFactory: requestFactory, + connection: connection + ) + + callFetchWrapper.addDependency(operations: [codingFactoryOperation]) + + let amountDetailsWrapper = createSpendAmountExtractionWrapper( + dependingOn: callFetchWrapper.targetOperation, + codingFactoryOperation: codingFactoryOperation, + connection: connection, + requestFactory: requestFactory + ) + + amountDetailsWrapper.addDependency(wrapper: callFetchWrapper) + amountDetailsWrapper.addDependency(operations: [codingFactoryOperation]) + + let mapOperation = ClosureOperation { + let call = try callFetchWrapper.targetOperation.extractNoCancellableResultData() + let amountDetails = try amountDetailsWrapper.targetOperation.extractNoCancellableResultData() + + return ReferendumActionLocal(amountSpendDetails: amountDetails, call: call) + } + + mapOperation.addDependency(callFetchWrapper.targetOperation) + mapOperation.addDependency(amountDetailsWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + callFetchWrapper.allOperations + + amountDetailsWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } +} From d1757bd56ff36688fcd2511eeb85b8606ede8f23 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 7 Nov 2022 10:26:25 +0500 Subject: [PATCH 159/229] add gov1 action operation factory --- novawallet.xcodeproj/project.pbxproj | 24 ++- .../JSONRPC/RemoteStorageSizeRequest.swift | 5 + .../Democracy/Democracy+CodingPath.swift | 4 + .../Democracy/DemocracyProposalCall.swift | 26 +++ .../Action/Gov1ActionOperationFactory.swift | 171 ++++++++++++++++++ .../Gov2ActionOperationFactory.swift | 0 .../GovernanceActionOperationFactory.swift | 0 7 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 novawallet/Common/Network/JSONRPC/RemoteStorageSizeRequest.swift create mode 100644 novawallet/Common/Substrate/Types/Democracy/DemocracyProposalCall.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Action/Gov1ActionOperationFactory.swift rename novawallet/Modules/Vote/Governance/Operation/{ => Action}/Gov2ActionOperationFactory.swift (100%) rename novawallet/Modules/Vote/Governance/Operation/{ => Action}/GovernanceActionOperationFactory.swift (100%) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 5ff78648f0..07dc3a0388 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -963,6 +963,9 @@ 845B07FD291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */; }; 845B07FF2916F529005785D3 /* Gov1SubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B07FE2916F529005785D3 /* Gov1SubscriptionFactory.swift */; }; 845B08012918406A005785D3 /* Gov2ActionOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08002918406A005785D3 /* Gov2ActionOperationFactory.swift */; }; + 845B08042918C308005785D3 /* Gov1ActionOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08032918C308005785D3 /* Gov1ActionOperationFactory.swift */; }; + 845B08062918C3FB005785D3 /* DemocracyProposalCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08052918C3FB005785D3 /* DemocracyProposalCall.swift */; }; + 845B08082918C8DA005785D3 /* RemoteStorageSizeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08072918C8DA005785D3 /* RemoteStorageSizeRequest.swift */; }; 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811128F429BB0040CE84 /* SupportPallet.swift */; }; 845B811528F43C350040CE84 /* Treasury.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811428F43C350040CE84 /* Treasury.swift */; }; 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811628F43C730040CE84 /* TreasuryProposal.swift */; }; @@ -3928,6 +3931,9 @@ 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemocracyDecidingFunctionProtocol.swift; sourceTree = ""; }; 845B07FE2916F529005785D3 /* Gov1SubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1SubscriptionFactory.swift; sourceTree = ""; }; 845B08002918406A005785D3 /* Gov2ActionOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2ActionOperationFactory.swift; sourceTree = ""; }; + 845B08032918C308005785D3 /* Gov1ActionOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1ActionOperationFactory.swift; sourceTree = ""; }; + 845B08052918C3FB005785D3 /* DemocracyProposalCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemocracyProposalCall.swift; sourceTree = ""; }; + 845B08072918C8DA005785D3 /* RemoteStorageSizeRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteStorageSizeRequest.swift; sourceTree = ""; }; 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; @@ -8115,10 +8121,21 @@ 845B07F029159AE7005785D3 /* DemocracyVoting.swift */, 845B07F229159C15005785D3 /* Democracy+CodingPath.swift */, 845B07F629162AB3005785D3 /* Democracy+ConstantPath.swift */, + 845B08052918C3FB005785D3 /* DemocracyProposalCall.swift */, ); path = Democracy; sourceTree = ""; }; + 845B08022918C2E5005785D3 /* Action */ = { + isa = PBXGroup; + children = ( + 845B811E28F451A40040CE84 /* GovernanceActionOperationFactory.swift */, + 845B08002918406A005785D3 /* Gov2ActionOperationFactory.swift */, + 845B08032918C308005785D3 /* Gov1ActionOperationFactory.swift */, + ); + path = Action; + sourceTree = ""; + }; 845B811028F429AB0040CE84 /* Support */ = { isa = PBXGroup; children = ( @@ -10357,6 +10374,7 @@ 84A1742528ED60610096F943 /* Operation */ = { isa = PBXGroup; children = ( + 845B08022918C2E5005785D3 /* Action */, 843461F1290D370000379936 /* Locks */, 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */, 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, @@ -10365,8 +10383,6 @@ 845B07F4291627A3005785D3 /* Gov1OperationFactory+Protocol.swift */, 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */, 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, - 845B811E28F451A40040CE84 /* GovernanceActionOperationFactory.swift */, - 845B08002918406A005785D3 /* Gov2ActionOperationFactory.swift */, 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */, 8425D0EB28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift */, ); @@ -11422,6 +11438,7 @@ 84300B2B26C10C9B00D64514 /* ConnectionStateReporting.swift */, F4C201812728678400B0F3D0 /* ExtrinsicStatus.swift */, 846CF0CC2914DC25008A96A1 /* RemoteStateCallRequest.swift */, + 845B08072918C8DA005785D3 /* RemoteStorageSizeRequest.swift */, ); path = JSONRPC; sourceTree = ""; @@ -16599,6 +16616,7 @@ 88A95FA628F8664100BE26F3 /* ReferendumTimelineView.swift in Sources */, 843A2C7326A8641400266F53 /* MultiValueView.swift in Sources */, 3FF8EE1158A273D0D50BC7A6 /* StakingUnbondConfirmPresenter.swift in Sources */, + 845B08042918C308005785D3 /* Gov1ActionOperationFactory.swift in Sources */, F0C3DB0CEE1975626B0014A8 /* StakingUnbondConfirmInteractor.swift in Sources */, 849FA21628A26CB500F83EAA /* CountdownTimerMediator.swift in Sources */, D3B48F82A875E301D749AC0B /* StakingUnbondConfirmViewController.swift in Sources */, @@ -16663,6 +16681,7 @@ F47D328226C260CC00CF35A2 /* FWPieChartView.swift in Sources */, 84F1CB4027CF6BEF0095D523 /* UniquesClassDetails.swift in Sources */, 84FEADEE287837E8001DFC26 /* TuringRewardCalculatorService.swift in Sources */, + 845B08062918C3FB005785D3 /* DemocracyProposalCall.swift in Sources */, 78D94A761EFECED60F38232D /* CustomValidatorListViewController.swift in Sources */, 7401E7CAEEE6890BE74ACCE1 /* CustomValidatorListViewLayout.swift in Sources */, 84BFE89C28C23A2500140F1F /* AutomationTime.swift in Sources */, @@ -16780,6 +16799,7 @@ BE8CF97B6EA62C75277B78AA /* MoonbeamTermsProtocols.swift in Sources */, B316F0D2BDF0F44AD27F58E0 /* MoonbeamTermsWireframe.swift in Sources */, 8027EA456C0C13F6DA73D540 /* MoonbeamTermsPresenter.swift in Sources */, + 845B08082918C8DA005785D3 /* RemoteStorageSizeRequest.swift in Sources */, 8452585527ABF270004F9082 /* AssetListEmptyCell.swift in Sources */, D72773CE9AF638387DA9BA77 /* MoonbeamTermsInteractor.swift in Sources */, 2B1E63AF98584341D670FB40 /* MoonbeamTermsViewController.swift in Sources */, diff --git a/novawallet/Common/Network/JSONRPC/RemoteStorageSizeRequest.swift b/novawallet/Common/Network/JSONRPC/RemoteStorageSizeRequest.swift new file mode 100644 index 0000000000..027c086ddb --- /dev/null +++ b/novawallet/Common/Network/JSONRPC/RemoteStorageSizeRequest.swift @@ -0,0 +1,5 @@ +import Foundation + +enum RemoteStorageSize { + static var method: String { "state_getStorageSize" } +} diff --git a/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift b/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift index f9a4453fe7..0ce7992eb8 100644 --- a/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift +++ b/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift @@ -8,4 +8,8 @@ extension Democracy { static var votingOf: StorageCodingPath { StorageCodingPath(moduleName: "Democracy", itemName: "VotingOf") } + + static var preimages: StorageCodingPath { + StorageCodingPath(moduleName: "Democracy", itemName: "Preimages") + } } diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyProposalCall.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyProposalCall.swift new file mode 100644 index 0000000000..7590c2614c --- /dev/null +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyProposalCall.swift @@ -0,0 +1,26 @@ +import Foundation +import SubstrateSdk + +extension Democracy { + struct ProposalCallAvailable: Decodable { + @BytesCodable var data: Data + } + + enum ProposalCall: Decodable { + case available(ProposalCallAvailable) + case unknown + + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let type = try container.decode(String.self) + + switch type { + case "Available": + let model = try container.decode(ProposalCallAvailable.self) + self = .available(model) + default: + self = .unknown + } + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Action/Gov1ActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Action/Gov1ActionOperationFactory.swift new file mode 100644 index 0000000000..a76a3db5cb --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Action/Gov1ActionOperationFactory.swift @@ -0,0 +1,171 @@ +import Foundation +import RobinHood +import SubstrateSdk +import BigInt + +final class Gov1ActionOperationFactory: GovernanceActionOperationFactory { + let gov2OperationFactory: Gov2ActionOperationFactory + + init( + gov2OperationFactory: Gov2ActionOperationFactory, + requestFactory: StorageRequestFactoryProtocol, + operationQueue: OperationQueue + ) { + self.gov2OperationFactory = gov2OperationFactory + + super.init(requestFactory: requestFactory, operationQueue: operationQueue) + } + + private func createDemocracyPreimageWrapper( + dependingOn keyEncodingOperation: BaseOperation<[Data]>, + storageSizeOperation: BaseOperation, + connection: JSONRPCEngine, + codingFactory: RuntimeCoderFactoryProtocol + ) -> BaseOperation<[ReferendumActionLocal.Call>?]> { + OperationCombiningService>?>( + operationManager: OperationManager(operationQueue: operationQueue) + ) { + let result = try storageSizeOperation.extractNoCancellableResultData() + + if let size = BigUInt.fromHexString(result), size <= Self.maxFetchCallSize { + let callFetchWrapper: CompoundOperationWrapper<[StorageResponse]> = + self.requestFactory.queryItems( + engine: connection, + keys: { try keyEncodingOperation.extractNoCancellableResultData() }, + factory: { codingFactory }, + storagePath: Democracy.preimages + ) + + let mappingOperation = ClosureOperation>?> { + let responses = try callFetchWrapper.targetOperation.extractNoCancellableResultData() + guard case let .available(call) = responses.first?.value else { + return nil + } + + let decoder = try codingFactory.createDecoder(from: call.data) + + let optCall: RuntimeCall? = try? decoder.read( + of: GenericType.call.name, + with: codingFactory.createRuntimeJsonContext().toRawContext() + ) + + if let call = optCall { + return .concrete(call) + } else { + return nil + } + } + + mappingOperation.addDependency(callFetchWrapper.targetOperation) + + let wrapper = CompoundOperationWrapper( + targetOperation: mappingOperation, + dependencies: callFetchWrapper.allOperations + ) + + return [wrapper] + } else { + let wrapper = CompoundOperationWrapper>?>.createWithResult( + .tooLong + ) + return [wrapper] + } + }.longrunOperation() + } + + private func fetchDemocracyPreimage( + for hash: Data, + connection: JSONRPCEngine, + codingFactory: RuntimeCoderFactoryProtocol + ) -> CompoundOperationWrapper>?> { + let keyEncodingOperation = MapKeyEncodingOperation( + path: Democracy.preimages, + storageKeyFactory: StorageKeyFactory() + ) + + keyEncodingOperation.codingFactory = codingFactory + keyEncodingOperation.keyParams = [BytesCodable(wrappedValue: hash)] + + let storageSizeOperation = JSONRPCListOperation(engine: connection, method: RemoteStorageSize.method) + + storageSizeOperation.configurationBlock = { + do { + if let key = try keyEncodingOperation.extractNoCancellableResultData().first { + storageSizeOperation.parameters = [key.toHex(includePrefix: true)] + } else { + storageSizeOperation.result = .failure(CommonError.dataCorruption) + } + } catch { + storageSizeOperation.result = .failure(error) + } + } + + storageSizeOperation.addDependency(keyEncodingOperation) + + let combiningOperation = createDemocracyPreimageWrapper( + dependingOn: keyEncodingOperation, + storageSizeOperation: storageSizeOperation, + connection: connection, + codingFactory: codingFactory + ) + + combiningOperation.addDependency(storageSizeOperation) + + let mappingOperation = ClosureOperation>?> { + guard let action = try combiningOperation.extractNoCancellableResultData().first else { + return nil + } + + return action + } + + mappingOperation.addDependency(combiningOperation) + + let dependencies = [keyEncodingOperation, storageSizeOperation, combiningOperation] + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) + } + + override func fetchCall( + for hash: Data, + connection: JSONRPCEngine, + codingFactoryOperation: BaseOperation + ) -> CompoundOperationWrapper>?> { + let fetchOperation = OperationCombiningService>?>( + operationManager: OperationManager(operationQueue: operationQueue) + ) { + let codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + + let callPath = Democracy.preimages + if codingFactory.metadata.getCall(from: callPath.moduleName, with: callPath.itemName) != nil { + let wrapper = self.fetchDemocracyPreimage( + for: hash, + connection: connection, + codingFactory: codingFactory + ) + + return [wrapper] + } else { + let wrapper = self.gov2OperationFactory.fetchCall( + for: hash, + connection: connection, + codingFactoryOperation: codingFactoryOperation + ) + + return [wrapper] + } + }.longrunOperation() + + let mappingOperation = ClosureOperation>?> { + guard let action = try fetchOperation.extractNoCancellableResultData().first else { + return nil + } + + return action + } + + mappingOperation.addDependency(fetchOperation) + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: [fetchOperation]) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Action/Gov2ActionOperationFactory.swift similarity index 100% rename from novawallet/Modules/Vote/Governance/Operation/Gov2ActionOperationFactory.swift rename to novawallet/Modules/Vote/Governance/Operation/Action/Gov2ActionOperationFactory.swift diff --git a/novawallet/Modules/Vote/Governance/Operation/GovernanceActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Action/GovernanceActionOperationFactory.swift similarity index 100% rename from novawallet/Modules/Vote/Governance/Operation/GovernanceActionOperationFactory.swift rename to novawallet/Modules/Vote/Governance/Operation/Action/GovernanceActionOperationFactory.swift From e87e716279bd793780586b9e4e8a074d6edc68ba Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 7 Nov 2022 11:05:04 +0500 Subject: [PATCH 160/229] add gov1 extrinsics --- novawallet.xcodeproj/project.pbxproj | 30 ++- .../Calls/Democracy/Democracy+Call.swift | 34 +++ .../Extrinsics/Gov1ExtrinsicFactory.swift | 52 +++++ .../Gov2ExtrinsicFactory.swift | 9 +- .../GovernanceExtrinsicFactory.swift | 11 + .../ViewModel/ReferendumsModelFactory.swift | 201 +++++++++++------- 6 files changed, 254 insertions(+), 83 deletions(-) create mode 100644 novawallet/Common/Substrate/Calls/Democracy/Democracy+Call.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Extrinsics/Gov1ExtrinsicFactory.swift rename novawallet/Modules/Vote/Governance/Operation/{ => Extrinsics}/Gov2ExtrinsicFactory.swift (86%) create mode 100644 novawallet/Modules/Vote/Governance/Operation/Extrinsics/GovernanceExtrinsicFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 07dc3a0388..ca279331cb 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -966,6 +966,9 @@ 845B08042918C308005785D3 /* Gov1ActionOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08032918C308005785D3 /* Gov1ActionOperationFactory.swift */; }; 845B08062918C3FB005785D3 /* DemocracyProposalCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08052918C3FB005785D3 /* DemocracyProposalCall.swift */; }; 845B08082918C8DA005785D3 /* RemoteStorageSizeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08072918C8DA005785D3 /* RemoteStorageSizeRequest.swift */; }; + 845B080A2918D381005785D3 /* Gov1ExtrinsicFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08092918D381005785D3 /* Gov1ExtrinsicFactory.swift */; }; + 845B080D2918D4F8005785D3 /* Democracy+Call.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B080C2918D4F8005785D3 /* Democracy+Call.swift */; }; + 845B08102918D65E005785D3 /* GovernanceExtrinsicFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B080F2918D65E005785D3 /* GovernanceExtrinsicFactory.swift */; }; 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811128F429BB0040CE84 /* SupportPallet.swift */; }; 845B811528F43C350040CE84 /* Treasury.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811428F43C350040CE84 /* Treasury.swift */; }; 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811628F43C730040CE84 /* TreasuryProposal.swift */; }; @@ -3934,6 +3937,9 @@ 845B08032918C308005785D3 /* Gov1ActionOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1ActionOperationFactory.swift; sourceTree = ""; }; 845B08052918C3FB005785D3 /* DemocracyProposalCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemocracyProposalCall.swift; sourceTree = ""; }; 845B08072918C8DA005785D3 /* RemoteStorageSizeRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteStorageSizeRequest.swift; sourceTree = ""; }; + 845B08092918D381005785D3 /* Gov1ExtrinsicFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1ExtrinsicFactory.swift; sourceTree = ""; }; + 845B080C2918D4F8005785D3 /* Democracy+Call.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Democracy+Call.swift"; sourceTree = ""; }; + 845B080F2918D65E005785D3 /* GovernanceExtrinsicFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceExtrinsicFactory.swift; sourceTree = ""; }; 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; @@ -8136,6 +8142,24 @@ path = Action; sourceTree = ""; }; + 845B080B2918D4E9005785D3 /* Democracy */ = { + isa = PBXGroup; + children = ( + 845B080C2918D4F8005785D3 /* Democracy+Call.swift */, + ); + path = Democracy; + sourceTree = ""; + }; + 845B080E2918D64B005785D3 /* Extrinsics */ = { + isa = PBXGroup; + children = ( + 845B080F2918D65E005785D3 /* GovernanceExtrinsicFactory.swift */, + 8425D0EB28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift */, + 845B08092918D381005785D3 /* Gov1ExtrinsicFactory.swift */, + ); + path = Extrinsics; + sourceTree = ""; + }; 845B811028F429AB0040CE84 /* Support */ = { isa = PBXGroup; children = ( @@ -8176,6 +8200,7 @@ 845BB8C725E45D0600E5FCDC /* Calls */ = { isa = PBXGroup; children = ( + 845B080B2918D4E9005785D3 /* Democracy */, 84A9ECBE29128D130094C763 /* ConvictionVoting */, 844ADE7C28CB34F600EE29F7 /* AutomationTime */, 84EBFCEC285E82AB0006327E /* Xcm */, @@ -10374,6 +10399,7 @@ 84A1742528ED60610096F943 /* Operation */ = { isa = PBXGroup; children = ( + 845B080E2918D64B005785D3 /* Extrinsics */, 845B08022918C2E5005785D3 /* Action */, 843461F1290D370000379936 /* Locks */, 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */, @@ -10384,7 +10410,6 @@ 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */, 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */, - 8425D0EB28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift */, ); path = Operation; sourceTree = ""; @@ -16504,6 +16529,7 @@ AEF507AF262423FD0098574D /* HmacSigner.swift in Sources */, 3229E306230161AA99B14BDD /* StakingRewardPayoutsViewFactory.swift in Sources */, 8473D4002657E8BB00B394B2 /* CrowdloanFunds.swift in Sources */, + 845B08102918D65E005785D3 /* GovernanceExtrinsicFactory.swift in Sources */, 7E1A03082260E0D31AD394CA /* StakingRewardDetailsProtocols.swift in Sources */, 65909D701527D99837B439D9 /* StakingRewardDetailsWireframe.swift in Sources */, 84350ACC284569560031EF24 /* ParaStkCollatorInfoViewController.swift in Sources */, @@ -16813,6 +16839,7 @@ 5E621A350A6DDD78597CC9E5 /* CrowdloanYourContributionsWireframe.swift in Sources */, 716F0819BAB14322E34E416C /* CrowdloanYourContributionsPresenter.swift in Sources */, F0675F495766D07473B065F7 /* CrowdloanYourContributionsInteractor.swift in Sources */, + 845B080D2918D4F8005785D3 /* Democracy+Call.swift in Sources */, 8425D0EE28FE9BF1003B782A /* ReferendumVoteAction.swift in Sources */, 6857DAF09C8D7D5F9C5A5000 /* CrowdloanYourContributionsViewController.swift in Sources */, 487A912B697604FE3367FAEC /* CrowdloanYourContributionsViewLayout.swift in Sources */, @@ -16851,6 +16878,7 @@ E325FBFE10A037E58525DA66 /* DAppSearchViewFactory.swift in Sources */, 65C06FCE82EEC0B476DB1CEF /* DAppBrowserProtocols.swift in Sources */, 84FBDBE328C884F000CC1037 /* ParaStkYieldBoostStorageSubscriptionHandler.swift in Sources */, + 845B080A2918D381005785D3 /* Gov1ExtrinsicFactory.swift in Sources */, 846A836128B8DB7700D92892 /* MessageSheetTimerLabel.swift in Sources */, 40087CC8E6A91976807F7D44 /* DAppBrowserWireframe.swift in Sources */, 37E229641DCDF64AC5AF1DCD /* DAppBrowserPresenter.swift in Sources */, diff --git a/novawallet/Common/Substrate/Calls/Democracy/Democracy+Call.swift b/novawallet/Common/Substrate/Calls/Democracy/Democracy+Call.swift new file mode 100644 index 0000000000..d7f3966d42 --- /dev/null +++ b/novawallet/Common/Substrate/Calls/Democracy/Democracy+Call.swift @@ -0,0 +1,34 @@ +import Foundation +import SubstrateSdk + +extension Democracy { + struct VoteCall: Codable { + enum CodingKeys: String, CodingKey { + case referendumIndex = "ref_index" + case vote + } + + @StringCodable var referendumIndex: Referenda.ReferendumIndex + let vote: ConvictionVoting.AccountVote + + var runtimeCall: RuntimeCall { + RuntimeCall(moduleName: "Democracy", callName: "vote", args: self) + } + } + + struct RemoveVoteCall: Codable { + @StringCodable var index: Referenda.ReferendumIndex + + var runtimeCall: RuntimeCall { + RuntimeCall(moduleName: "Democracy", callName: "remove_vote", args: self) + } + } + + struct UnlockCall: Codable { + let target: MultiAddress + + var runtimeCall: RuntimeCall { + RuntimeCall(moduleName: "Democracy", callName: "unlock", args: self) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Extrinsics/Gov1ExtrinsicFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Extrinsics/Gov1ExtrinsicFactory.swift new file mode 100644 index 0000000000..81ef5630c4 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Extrinsics/Gov1ExtrinsicFactory.swift @@ -0,0 +1,52 @@ +import Foundation +import SubstrateSdk + +final class Gov1ExtrinsicFactory: GovernanceExtrinsicFactory, GovernanceExtrinsicFactoryProtocol { + func vote( + _ action: ReferendumVoteAction, + referendum: ReferendumIdLocal, + builder: ExtrinsicBuilderProtocol + ) throws -> ExtrinsicBuilderProtocol { + let accountVote = ConvictionVoting.AccountVote.standard( + .init( + vote: .init(aye: action.isAye, conviction: action.conviction), + balance: action.amount + ) + ) + + let voteCall = Democracy.VoteCall( + referendumIndex: Referenda.ReferendumIndex(referendum), + vote: accountVote + ) + + return try builder.adding(call: voteCall.runtimeCall) + } + + func unlock( + with actions: Set, + accountId: AccountId, + builder: ExtrinsicBuilderProtocol + ) throws -> ExtrinsicBuilderProtocol { + let removeVoteCalls: [RuntimeCall] = actions.compactMap { action in + switch action { + case let .unvote(_, index): + return Democracy.RemoveVoteCall(index: Referenda.ReferendumIndex(index)).runtimeCall + case .unlock: + return nil + } + } + + let unlockCalls: [RuntimeCall] = actions.compactMap { action in + switch action { + case .unlock: + return Democracy.UnlockCall(target: .accoundId(accountId)).runtimeCall + case .unvote: + return nil + } + } + + let newBuilder = try appendCalls(removeVoteCalls, builder: builder) + + return try appendCalls(unlockCalls, builder: newBuilder) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Extrinsics/Gov2ExtrinsicFactory.swift similarity index 86% rename from novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift rename to novawallet/Modules/Vote/Governance/Operation/Extrinsics/Gov2ExtrinsicFactory.swift index da85192454..960c7ec0eb 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2ExtrinsicFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Extrinsics/Gov2ExtrinsicFactory.swift @@ -1,7 +1,7 @@ import Foundation import SubstrateSdk -final class Gov2ExtrinsicFactory: GovernanceExtrinsicFactoryProtocol { +final class Gov2ExtrinsicFactory: GovernanceExtrinsicFactory, GovernanceExtrinsicFactoryProtocol { func vote( _ action: ReferendumVoteAction, referendum: ReferendumIdLocal, @@ -55,11 +55,4 @@ final class Gov2ExtrinsicFactory: GovernanceExtrinsicFactoryProtocol { return try appendCalls(unlockCalls, builder: newBuilder) } - - private func appendCalls( - _ calls: [C], - builder: ExtrinsicBuilderProtocol - ) throws -> ExtrinsicBuilderProtocol { - try calls.reduce(builder) { try $0.adding(call: $1) } - } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Extrinsics/GovernanceExtrinsicFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Extrinsics/GovernanceExtrinsicFactory.swift new file mode 100644 index 0000000000..c372fa7d17 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Extrinsics/GovernanceExtrinsicFactory.swift @@ -0,0 +1,11 @@ +import Foundation +import SubstrateSdk + +class GovernanceExtrinsicFactory { + func appendCalls( + _ calls: [C], + builder: ExtrinsicBuilderProtocol + ) throws -> ExtrinsicBuilderProtocol { + try calls.reduce(builder) { try $0.adding(call: $1) } + } +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 131d46beaf..35577f5a5b 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -147,48 +147,53 @@ final class ReferendumsModelFactory { let title = createPreparingStatus(for: model, locale: locale) + let votingProgressViewModel: VotingProgressView.Model + switch model.voting { case let .supportAndVotes(supportAndVotes): - let progressViewModel = createVotingProgressViewModel( + votingProgressViewModel = createGov2VotingProgressViewModel( supportAndVotes: supportAndVotes, chain: params.chainInfo.chain, currentBlock: params.chainInfo.currentBlock, locale: locale ) - let yourVotesModel = createVotesViewModel( - votes: params.votes, - chainAsset: params.chainInfo.chain.utilityAsset(), - locale: locale - ) + case let .threshold(threshold): + votingProgressViewModel = createGov1VotingProgressViewModel(votingThreshold: threshold, locale: locale) + } - let track = ReferendumTrackType.createViewModel( - from: model.track.name, - chain: params.chainInfo.chain, - locale: locale - ) + let yourVotesModel = createVotesViewModel( + votes: params.votes, + chainAsset: params.chainInfo.chain.utilityAsset(), + locale: locale + ) - let referendumNumber = localizedIndexFormatter.value(for: locale).string( - from: NSNumber(value: params.referendum.index) - ) + let track = ReferendumTrackType.createViewModel( + from: model.track.name, + chain: params.chainInfo.chain, + locale: locale + ) - let referendumTitle = referendumMetadataViewModelFactory.createTitle( - for: params.referendum, - metadata: params.metadata, - locale: locale - ) + let referendumNumber = localizedIndexFormatter.value(for: locale).string( + from: NSNumber(value: params.referendum.index) + ) - return .init( - referendumInfo: .init( - status: .init(name: title.uppercased(), kind: .neutral), - time: timeModel?.viewModel, - title: referendumTitle, - track: track, - referendumNumber: referendumNumber - ), - progress: progressViewModel, - yourVotes: yourVotesModel - ) - } + let referendumTitle = referendumMetadataViewModelFactory.createTitle( + for: params.referendum, + metadata: params.metadata, + locale: locale + ) + + return .init( + referendumInfo: .init( + status: .init(name: title.uppercased(), kind: .neutral), + time: timeModel?.viewModel, + title: referendumTitle, + track: track, + referendumNumber: referendumNumber + ), + progress: votingProgressViewModel, + yourVotes: yourVotesModel + ) } private func createVotesViewModel( @@ -236,59 +241,69 @@ final class ReferendumsModelFactory { params: StatusParams, locale: Locale ) -> ReferendumView.Model { + let votingProgressViewModel: VotingProgressView.Model + let isPassing: Bool + switch model.voting { case let .supportAndVotes(supportAndVotes): - let timeModel = statusViewModelFactory.createTimeViewModel( - for: params.referendum, - currentBlock: params.chainInfo.currentBlock, - blockDuration: params.chainInfo.blockDuration, - locale: locale - ) - - let progressViewModel = createVotingProgressViewModel( + votingProgressViewModel = createGov2VotingProgressViewModel( supportAndVotes: supportAndVotes, chain: params.chainInfo.chain, currentBlock: params.chainInfo.currentBlock, locale: locale ) - let isPassing = supportAndVotes.isPassing(at: params.chainInfo.currentBlock) - let statusName = isPassing ? - Strings.governanceReferendumsStatusPassing(preferredLanguages: locale.rLanguages) : - Strings.governanceReferendumsStatusNotPassing(preferredLanguages: locale.rLanguages) - let statusKind: ReferendumInfoView.StatusKind = isPassing ? .positive : .negative - let yourVotesModel = createVotesViewModel( - votes: params.votes, - chainAsset: params.chainInfo.chain.utilityAsset(), - locale: locale - ) - let track = ReferendumTrackType.createViewModel( - from: model.track.name, - chain: params.chainInfo.chain, - locale: locale - ) + isPassing = supportAndVotes.isPassing(at: params.chainInfo.currentBlock) + case let .threshold(threshold): + votingProgressViewModel = createGov1VotingProgressViewModel(votingThreshold: threshold, locale: locale) - let indexFormatter = localizedIndexFormatter.value(for: locale) - let referendumNumber = indexFormatter.string(from: NSNumber(value: params.referendum.index)) + isPassing = threshold.isPassing() + } - let referendumTitle = referendumMetadataViewModelFactory.createTitle( - for: params.referendum, - metadata: params.metadata, - locale: locale - ) + let timeModel = statusViewModelFactory.createTimeViewModel( + for: params.referendum, + currentBlock: params.chainInfo.currentBlock, + blockDuration: params.chainInfo.blockDuration, + locale: locale + ) - return .init( - referendumInfo: .init( - status: .init(name: statusName.uppercased(), kind: statusKind), - time: timeModel?.viewModel, - title: referendumTitle, - track: track, - referendumNumber: referendumNumber - ), - progress: progressViewModel, - yourVotes: yourVotesModel - ) - } + let statusName = isPassing ? + Strings.governanceReferendumsStatusPassing(preferredLanguages: locale.rLanguages) : + Strings.governanceReferendumsStatusNotPassing(preferredLanguages: locale.rLanguages) + + let statusKind: ReferendumInfoView.StatusKind = isPassing ? .positive : .negative + let yourVotesModel = createVotesViewModel( + votes: params.votes, + chainAsset: params.chainInfo.chain.utilityAsset(), + locale: locale + ) + + let track = ReferendumTrackType.createViewModel( + from: model.track.name, + chain: params.chainInfo.chain, + locale: locale + ) + + let indexFormatter = localizedIndexFormatter.value(for: locale) + let referendumNumber = indexFormatter.string(from: NSNumber(value: params.referendum.index)) + + let referendumTitle = referendumMetadataViewModelFactory.createTitle( + for: params.referendum, + metadata: params.metadata, + locale: locale + ) + + return .init( + referendumInfo: .init( + status: .init(name: statusName.uppercased(), kind: statusKind), + time: timeModel?.viewModel, + title: referendumTitle, + track: track, + referendumNumber: referendumNumber + ), + progress: votingProgressViewModel, + yourVotes: yourVotesModel + ) } private func provideApprovedReferendumCellViewModel( @@ -412,7 +427,36 @@ final class ReferendumsModelFactory { ) } - private func createVotingProgressViewModel( + private func createVotingThresholdProgressViewModel( + for votingThreshold: VotingThresholdLocal, + locale: Locale + ) -> VotingProgressView.ApprovalModel { + let ayeProgressString: String + let nayProgressString: String + + let percentFormatter = localizedPercentFormatter.value(for: locale) + + if let approvalFraction = votingThreshold.approvalFraction { + ayeProgressString = percentFormatter.stringFromDecimal(approvalFraction) ?? "" + nayProgressString = percentFormatter.stringFromDecimal(1 - approvalFraction) ?? "" + } else { + ayeProgressString = percentFormatter.stringFromDecimal(0) ?? "" + nayProgressString = percentFormatter.stringFromDecimal(0) ?? "" + } + + let passThreshold = votingThreshold.calculateThreshold() ?? 0 + let passThresholdString = percentFormatter.stringFromDecimal(passThreshold) ?? "" + + return .init( + passThreshold: passThreshold, + ayeProgress: votingThreshold.approvalFraction, + ayeMessage: Strings.governanceAyesFormat(ayeProgressString, preferredLanguages: locale.rLanguages), + passMessage: Strings.governanceToPassFormat(passThresholdString, preferredLanguages: locale.rLanguages), + nayMessage: Strings.governanceNaysFormat(nayProgressString, preferredLanguages: locale.rLanguages) + ) + } + + private func createGov2VotingProgressViewModel( supportAndVotes: SupportAndVotesLocal, chain: ChainModel, currentBlock: BlockNumber, @@ -433,6 +477,15 @@ final class ReferendumsModelFactory { return .init(support: supportModel, approval: approvalModel) } + + private func createGov1VotingProgressViewModel( + votingThreshold: VotingThresholdLocal, + locale: Locale + ) -> VotingProgressView.Model { + let thresholdViewModel = createVotingThresholdProgressViewModel(for: votingThreshold, locale: locale) + + return .init(support: nil, approval: thresholdViewModel) + } } extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { From aed98f3405e92f45302e0532621b4e008566a455 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 7 Nov 2022 12:23:19 +0500 Subject: [PATCH 161/229] referendums list parsing fix --- novawallet.xcodeproj/project.pbxproj | 4 +- .../Migration/SubstrateStorageVersion.swift | 3 + .../Model/ChainRegistry/ChainModel.swift | 8 + .../EntityToModel/ChainModelMapper.swift | 7 +- .../.xccurrentversion | 2 +- .../SubstrateDataModel4.xcdatamodel/contents | 166 ++++++++++++++++++ .../Storage/SubstrateDataStorageFacade.swift | 2 +- .../Democracy/Democracy+CodingPath.swift | 2 +- .../Substrate/Types/Democracy/Democracy.swift | 4 +- .../Types/Democracy/DemocracyReferendum.swift | 7 +- .../Model/GovernanceSharedState.swift | 95 ++++++++-- .../Operation/Gov1LocalMappingFactory.swift | 2 +- .../Operation/Gov1OperationFactory.swift | 4 +- .../Referendums/ReferendumsInteractor.swift | 20 ++- .../Parent/VoteChildPresenterFactory.swift | 6 - 15 files changed, 288 insertions(+), 44 deletions(-) create mode 100644 novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel4.xcdatamodel/contents diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index ca279331cb..081f4b3aac 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -3940,6 +3940,7 @@ 845B08092918D381005785D3 /* Gov1ExtrinsicFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1ExtrinsicFactory.swift; sourceTree = ""; }; 845B080C2918D4F8005785D3 /* Democracy+Call.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Democracy+Call.swift"; sourceTree = ""; }; 845B080F2918D65E005785D3 /* GovernanceExtrinsicFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceExtrinsicFactory.swift; sourceTree = ""; }; + 845B08112918E343005785D3 /* SubstrateDataModel4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SubstrateDataModel4.xcdatamodel; sourceTree = ""; }; 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; @@ -18120,11 +18121,12 @@ 843910CA253F7E6500E3C217 /* SubstrateDataModel.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 845B08112918E343005785D3 /* SubstrateDataModel4.xcdatamodel */, 84D8754628EB726E004065BD /* SubstrateDataModel3.xcdatamodel */, 88787F0328DB3A7B00B115AB /* SubstrateDataModel2.xcdatamodel */, 843910CB253F7E6500E3C217 /* SubstrateDataModel.xcdatamodel */, ); - currentVersion = 84D8754628EB726E004065BD /* SubstrateDataModel3.xcdatamodel */; + currentVersion = 845B08112918E343005785D3 /* SubstrateDataModel4.xcdatamodel */; path = SubstrateDataModel.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/novawallet/Common/Migration/SubstrateStorageVersion.swift b/novawallet/Common/Migration/SubstrateStorageVersion.swift index 1bb0b326bf..f140884cc1 100644 --- a/novawallet/Common/Migration/SubstrateStorageVersion.swift +++ b/novawallet/Common/Migration/SubstrateStorageVersion.swift @@ -2,6 +2,7 @@ enum SubstrateStorageVersion: String, CaseIterable { case version1 = "SubstrateDataModel" case version2 = "SubstrateDataModel2" case version3 = "SubstrateDataModel3" + case version4 = "SubstrateDataModel4" static var current: SubstrateStorageVersion { allCases.last! @@ -14,6 +15,8 @@ enum SubstrateStorageVersion: String, CaseIterable { case .version2: return .version3 case .version3: + return .version4 + case .version4: return nil } } diff --git a/novawallet/Common/Model/ChainRegistry/ChainModel.swift b/novawallet/Common/Model/ChainRegistry/ChainModel.swift index 1a1b46ea9e..5812e8f5ad 100644 --- a/novawallet/Common/Model/ChainRegistry/ChainModel.swift +++ b/novawallet/Common/Model/ChainRegistry/ChainModel.swift @@ -123,6 +123,14 @@ struct ChainModel: Equatable, Codable, Hashable { options?.contains(where: { $0 == .governance || $0 == .governanceV1 }) ?? false } + var hasGov1: Bool { + options?.contains(where: { $0 == .governanceV1 }) ?? false + } + + var hasGov2: Bool { + options?.contains(where: { $0 == .governance }) ?? false + } + var isRelaychain: Bool { parentId == nil } func utilityAssets() -> Set { diff --git a/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift b/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift index 34e6fde386..8af73dbc3b 100644 --- a/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift +++ b/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift @@ -258,6 +258,10 @@ extension ChainModelMapper: CoreDataMapperProtocol { options.append(.governance) } + if entity.hasGovernanceV1 { + options.append(.governanceV1) + } + let externalApiSet = createExternalApi(from: entity) let explorers = createExplorers(from: entity) @@ -298,7 +302,8 @@ extension ChainModelMapper: CoreDataMapperProtocol { entity.isEthereumBased = model.isEthereumBased entity.isTestnet = model.isTestnet entity.hasCrowdloans = model.hasCrowdloans - entity.hasGovernance = model.hasGovernance + entity.hasGovernanceV1 = model.hasGov1 + entity.hasGovernance = model.hasGov2 entity.order = model.order entity.additional = try model.additional.map { try jsonEncoder.encode($0) diff --git a/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion index 0d3a209131..7cfd904579 100644 --- a/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion +++ b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - SubstrateDataModel3.xcdatamodel + SubstrateDataModel4.xcdatamodel diff --git a/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel4.xcdatamodel/contents b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel4.xcdatamodel/contents new file mode 100644 index 0000000000..a1876740fe --- /dev/null +++ b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel4.xcdatamodel/contents @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/novawallet/Common/Storage/SubstrateDataStorageFacade.swift b/novawallet/Common/Storage/SubstrateDataStorageFacade.swift index 8932c422d7..01736c6ce8 100644 --- a/novawallet/Common/Storage/SubstrateDataStorageFacade.swift +++ b/novawallet/Common/Storage/SubstrateDataStorageFacade.swift @@ -4,7 +4,7 @@ import CoreData enum SubstrateStorageParams { static let databaseName = "SubstrateDataModel.sqlite" static let modelDirectory: String = "SubstrateDataModel.momd" - static let modelVersion: SubstrateStorageVersion = .version3 + static let modelVersion: SubstrateStorageVersion = .version4 static let storageDirectoryURL: URL = { let baseURL = FileManager.default.urls( diff --git a/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift b/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift index 0ce7992eb8..235b394da1 100644 --- a/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift +++ b/novawallet/Common/Substrate/Types/Democracy/Democracy+CodingPath.swift @@ -2,7 +2,7 @@ import Foundation extension Democracy { static var referendumInfo: StorageCodingPath { - StorageCodingPath(moduleName: "Democracy", itemName: "ReferendumInfoFor") + StorageCodingPath(moduleName: "Democracy", itemName: "ReferendumInfoOf") } static var votingOf: StorageCodingPath { diff --git a/novawallet/Common/Substrate/Types/Democracy/Democracy.swift b/novawallet/Common/Substrate/Types/Democracy/Democracy.swift index 43c41e59fb..e860f5123d 100644 --- a/novawallet/Common/Substrate/Types/Democracy/Democracy.swift +++ b/novawallet/Common/Substrate/Types/Democracy/Democracy.swift @@ -1,3 +1,5 @@ import Foundation -enum Democracy {} +enum Democracy { + static var lockId: String = "democrac" +} diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift index b61f4ed017..a33590a3fa 100644 --- a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift @@ -17,17 +17,12 @@ extension Democracy { struct OngoingStatus: Decodable { @StringCodable var end: BlockNumber @StringCodable var delay: BlockNumber - @SupportPallet.HashOrBoundedCallWrapper var proposal: SupportPallet.Bounded> + @SupportPallet.HashOrBoundedCallWrapper var proposalHash: SupportPallet.Bounded> let threshold: Democracy.VoteThreshold let tally: Tally } struct FinishedStatus: Decodable { - enum CodingKeys: String, CodingKey { - case approved = "0" - case end = "1" - } - let approved: Bool @StringCodable var end: BlockNumber } diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index 1e0a8a844c..ba907c9c39 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -5,13 +5,14 @@ import SubstrateSdk final class GovernanceSharedState { let settings: GovernanceChainSettings - let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol + let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol let requestFactory: StorageRequestFactoryProtocol let chainRegistry: ChainRegistryProtocol let operationQueue: OperationQueue private(set) var subscriptionFactory: GovernanceSubscriptionFactoryProtocol? + private(set) var operationFactory: ReferendumsOperationFactoryProtocol? private(set) var blockTimeService: BlockTimeEstimationServiceProtocol? init( @@ -50,22 +51,86 @@ final class GovernanceSharedState { blockTimeService = newService } - func replaceSubscriptionFactory(for chain: ChainModel?) { - guard let chainId = chain?.chainId else { - subscriptionFactory = nil + func replaceGovernanceFactory(for chain: ChainModel?) { + subscriptionFactory = nil + operationFactory = nil + + guard let chain = chain else { return } - let operationFactory = Gov2OperationFactory( - requestFactory: requestFactory, - operationQueue: OperationManagerFacade.sharedDefaultQueue - ) - - subscriptionFactory = Gov2SubscriptionFactory( - chainId: chainId, - operationFactory: operationFactory, - chainRegistry: chainRegistry, - operationQueue: operationQueue - ) + let chainId = chain.chainId + + if chain.hasGov2 { + let operationFactory = Gov2OperationFactory( + requestFactory: requestFactory, + operationQueue: operationQueue + ) + + self.operationFactory = operationFactory + + subscriptionFactory = Gov2SubscriptionFactory( + chainId: chainId, + operationFactory: operationFactory, + chainRegistry: chainRegistry, + operationQueue: operationQueue + ) + } else if chain.hasGov1 { + let operationFactory = Gov1OperationFactory( + requestFactory: requestFactory, + operationQueue: operationQueue + ) + + self.operationFactory = operationFactory + + subscriptionFactory = Gov1SubscriptionFactory( + chainId: chainId, + operationFactory: operationFactory, + chainRegistry: chainRegistry, + operationQueue: operationQueue + ) + } + } + + func createExtrinsicFactory(for chain: ChainModel) -> GovernanceExtrinsicFactoryProtocol? { + if chain.hasGov2 { + return Gov2ExtrinsicFactory() + } else if chain.hasGov1 { + return Gov1ExtrinsicFactory() + } else { + return nil + } + } + + func createActionsDetailsFactory(for chain: ChainModel) -> ReferendumActionOperationFactoryProtocol? { + if chain.hasGov2 { + return Gov2ActionOperationFactory( + requestFactory: requestFactory, + operationQueue: operationQueue + ) + } else if chain.hasGov1 { + let gov2ActionsFactory = Gov2ActionOperationFactory( + requestFactory: requestFactory, + operationQueue: operationQueue + ) + + return Gov1ActionOperationFactory( + gov2OperationFactory: gov2ActionsFactory, + requestFactory: requestFactory, + operationQueue: operationQueue + ) + } else { + return nil + } + } + + func governanceId(for chain: ChainModel) -> String? { + if chain.hasGov2 { + return ConvictionVoting.lockId + } else if chain.hasGov1 { + return Democracy.lockId + } else { + return nil + } } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift index 1d7dec78fc..0d9e55707b 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift @@ -20,7 +20,7 @@ final class Gov1LocalMappingFactory { let state = ReferendumStateLocal.Deciding( track: track, - proposal: referendum.proposal, + proposal: referendum.proposalHash, voting: .threshold(voting), submitted: submitted, since: submitted, diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift index 5e7a2c2741..4ea2c81a45 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift @@ -68,7 +68,9 @@ final class Gov1OperationFactory { mapOperation.addDependency(totalIssuanceWrapper.targetOperation) mapOperation.addDependency(enactmentPeriodOperation) - return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: [votingPeriodOperation]) + let dependencies = [votingPeriodOperation, enactmentPeriodOperation] + totalIssuanceWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } func createReferendumMapOperation( diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 82c646c8c5..a2ba36dd91 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -11,7 +11,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani let chainRegistry: ChainRegistryProtocol let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol - let referendumsOperationFactory: ReferendumsOperationFactoryProtocol let lockStateFactory: GovernanceLockStateFactoryProtocol let applicationHandler: ApplicationHandlerProtocol let serviceFactory: GovernanceServiceFactoryProtocol @@ -21,10 +20,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani governanceState.generalLocalSubscriptionFactory } - var govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { - governanceState.govMetadataLocalSubscriptionFactory - } - private var priceProvider: AnySingleValueProvider? private var assetBalanceProvider: StreamableProvider? private var blockNumberSubscription: AnyDataProvider? @@ -42,7 +37,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani chainRegistry: ChainRegistryProtocol, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, - referendumsOperationFactory: ReferendumsOperationFactoryProtocol, lockStateFactory: GovernanceLockStateFactoryProtocol, serviceFactory: GovernanceServiceFactoryProtocol, applicationHandler: ApplicationHandlerProtocol, @@ -54,7 +48,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani self.chainRegistry = chainRegistry self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory - self.referendumsOperationFactory = referendumsOperationFactory self.lockStateFactory = lockStateFactory self.serviceFactory = serviceFactory self.operationQueue = operationQueue @@ -92,7 +85,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani } private func clearSubscriptionFactory() { - governanceState.replaceSubscriptionFactory(for: nil) + governanceState.replaceGovernanceFactory(for: nil) } private func continueSetup() { @@ -145,7 +138,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani } private func setupSubscriptionFactory(for chain: ChainModel) { - governanceState.replaceSubscriptionFactory(for: chain) + governanceState.replaceGovernanceFactory(for: chain) } private func subscribeToBlockNumber(for chain: ChainModel) { @@ -238,6 +231,11 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani return } + guard let referendumsOperationFactory = governanceState.operationFactory else { + presenter?.didReceiveReferendums([]) + return + } + let wrapper = referendumsOperationFactory.fetchAllReferendumsWrapper( from: connection, runtimeProvider: runtimeProvider @@ -395,6 +393,10 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { } extension ReferendumsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataLocalStorageHandler { + var govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { + governanceState.govMetadataLocalSubscriptionFactory + } + func handleGovMetadata(result: Result, chain: ChainModel) { guard let currentChain = governanceState.settings.value, currentChain.chainId == chain.chainId else { return diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index e766538374..0b312386b0 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -107,11 +107,6 @@ final class VoteChildPresenterFactory { operationManager: OperationManager(operationQueue: operationQueue) ) - let referendumOperationFactory = Gov2OperationFactory( - requestFactory: requestFactory, - operationQueue: OperationManagerFacade.sharedDefaultQueue - ) - let serviceFactory = GovernanceServiceFactory( chainRegisty: chainRegistry, storageFacade: substrateStorageFacade, @@ -131,7 +126,6 @@ final class VoteChildPresenterFactory { chainRegistry: chainRegistry, walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, priceLocalSubscriptionFactory: priceProviderFactory, - referendumsOperationFactory: referendumOperationFactory, lockStateFactory: lockStateFactory, serviceFactory: serviceFactory, applicationHandler: applicationHandler, From edd0de2504c087f51c3d26e6d90aa1fd99a1fbdc Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 7 Nov 2022 14:23:12 +0300 Subject: [PATCH 162/229] fix short description --- .../View/ReferendumDetailsTitleView.swift | 54 ++++++++++------- .../ReferendumFullDescriptionViewLayout.swift | 26 +------- .../Governance/View/MarkdownView+load.swift | 60 +++++++++++++++++++ 3 files changed, 95 insertions(+), 45 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/View/MarkdownView+load.swift diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index eaaa9e2ea6..3293fd7777 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -1,5 +1,6 @@ import UIKit import SoraUI +import MarkdownView final class ReferendumDetailsTitleView: UIView { var accountIconSize: CGSize { @@ -38,13 +39,8 @@ final class ReferendumDetailsTitleView: UIView { $0.numberOfLines = 0 } - let textView: UITextView = .create { - $0.textColor = R.color.colorTransparentText() - $0.font = .regularSubheadline + let descriptionView: MarkdownView = .create { $0.isScrollEnabled = false - $0.isEditable = false - $0.textContainerInset = .zero - $0.textContainer.lineFragmentPadding = 0 } let moreButton: RoundedButton = .create { button in @@ -78,7 +74,7 @@ final class ReferendumDetailsTitleView: UIView { [ accountContainerView, titleLabel, - textView, + descriptionView, moreButton ] ) @@ -87,6 +83,16 @@ final class ReferendumDetailsTitleView: UIView { content.snp.makeConstraints { $0.edges.equalToSuperview() } + descriptionView.onRendered = { [weak self] contentHeight in + self?.updateMarkdownView(height: contentHeight) + } + } + + private func updateMarkdownView(height: CGFloat) { + descriptionView.snp.updateConstraints { + $0.height.equalTo(height) + $0.leading.trailing.equalToSuperview() + } } } @@ -121,22 +127,30 @@ extension ReferendumDetailsTitleView { accountContainerView.isHidden = true } - if let details = viewModel.details { - titleLabel.isHidden = false - textView.isHidden = false - - titleLabel.text = details.title - textView.text = details.description - - moreButton.imageWithTitleView?.title = R.string.localizable.commonReadMore( - preferredLanguages: locale.rLanguages - ) + bind(details: viewModel.details, locale: locale) + } - moreButton.isHidden = !details.shouldReadMore - } else { + private func bind(details: Details?, locale: Locale) { + guard let details = details else { titleLabel.isHidden = true - textView.isHidden = true + descriptionView.isHidden = true moreButton.isHidden = true + return + } + titleLabel.isHidden = false + titleLabel.text = details.title + + if !details.description.isEmpty { + descriptionView.isHidden = false + descriptionView.loadLimitedText( + markdownText: details.description, + maxLinesCount: 4 + ) } + + moreButton.imageWithTitleView?.title = R.string.localizable.commonReadMore( + preferredLanguages: locale.rLanguages + ) + moreButton.isHidden = !details.shouldReadMore } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift index c0d1c619fe..fd2c24f0ac 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift @@ -36,34 +36,10 @@ final class ReferendumFullDescriptionViewLayout: UIView { } func set(markdownText: String) { - markdownView.load( - markdown: markdownText, - css: css(), - plugins: plugins() - ) + markdownView.loadFull(markdownText: markdownText) } func set(title: String) { titleLabel.text = title } - - private func plugins() -> [String]? { - [ - URL(string: "https://cdnjs.cloudflare.com/ajax/libs/markdown-it-footnote/3.0.3/markdown-it-footnote.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-sub@1.0.0/index.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-sup@1.0.0/index.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-ins@3.0.1/dist/markdown-it-ins.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-mark@3.0.1/dist/markdown-it-mark.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-container@3.0.0/dist/markdown-it-container.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-deflist@2.1.0/dist/markdown-it-deflist.min.js") - ].compactMap { $0 } - .compactMap { try? String(contentsOf: $0, encoding: .utf8) } - } - - private func css() -> String? { - guard let color = R.color.colorNovaBlue()?.hexRGB else { - return nil - } - return "a { color: \(color); }" - } } diff --git a/novawallet/Modules/Vote/Governance/View/MarkdownView+load.swift b/novawallet/Modules/Vote/Governance/View/MarkdownView+load.swift new file mode 100644 index 0000000000..eff9d91a83 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/MarkdownView+load.swift @@ -0,0 +1,60 @@ +import MarkdownView +import CoreGraphics + +extension MarkdownView { + func loadFull(markdownText: String) { + load( + markdown: markdownText, + css: css(coloredLink: R.color.colorNovaBlue()), + plugins: plugins() + ) + } + + func loadLimitedText( + markdownText: String, + maxLinesCount: Int + ) { + let css = [ + css(coloredLink: R.color.colorNovaBlue()), + css(maxLinesCount: maxLinesCount) + ].compactMap { $0 }.joined(separator: "\n") + + return load( + markdown: markdownText, + enableImage: false, + css: css, + plugins: plugins() + ) + } + + private func plugins() -> [String]? { + [ + URL(string: "https://cdnjs.cloudflare.com/ajax/libs/markdown-it-footnote/3.0.3/markdown-it-footnote.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-sub@1.0.0/index.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-sup@1.0.0/index.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-ins@3.0.1/dist/markdown-it-ins.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-mark@3.0.1/dist/markdown-it-mark.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-container@3.0.0/dist/markdown-it-container.min.js"), + URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-deflist@2.1.0/dist/markdown-it-deflist.min.js") + ].compactMap { $0 } + .compactMap { try? String(contentsOf: $0, encoding: .utf8) } + } + + private func css(coloredLink color: UIColor?) -> String? { + guard let color = color else { + return nil + } + return "a { color: \(color); }" + } + + private func css(maxLinesCount: Int) -> String { + """ + p { + -webkit-line-clamp: \(maxLinesCount); + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + } + """ + } +} From da77e558bc95d5b0d4e7411bce99ab5186e37344 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 7 Nov 2022 14:25:05 +0300 Subject: [PATCH 163/229] added missed files --- novawallet.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index cedc63d640..8285f80e3d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2264,6 +2264,7 @@ 880855FC28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */; }; 88107D5F290133F8001AB0B0 /* RoundedView+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */; }; 88107D6129015FAB001AB0B0 /* TrackTagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */; }; + 882232E92919226000CBA7B3 /* MarkdownView+load.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882232E82919225E00CBA7B3 /* MarkdownView+load.swift */; }; 8824D4222902D92F0022D778 /* ReferendumFullDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */; }; 8824D424290324260022D778 /* PrettyPrintedJSONOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D423290324260022D778 /* PrettyPrintedJSONOperationFactory.swift */; }; 8824D42629032B410022D778 /* BlurredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D42529032B410022D778 /* BlurredView.swift */; }; @@ -5235,6 +5236,7 @@ 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RoundedView+Styles.swift"; sourceTree = ""; }; 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackTagsView.swift; sourceTree = ""; }; 8821119C96944A0E3526E93A /* StakingRedeemViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRedeemViewFactory.swift; sourceTree = ""; }; + 882232E82919225E00CBA7B3 /* MarkdownView+load.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MarkdownView+load.swift"; sourceTree = ""; }; 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsInteractor.swift; sourceTree = ""; }; 8824D423290324260022D778 /* PrettyPrintedJSONOperationFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrettyPrintedJSONOperationFactory.swift; sourceTree = ""; }; 8824D42529032B410022D778 /* BlurredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurredView.swift; sourceTree = ""; }; @@ -12388,6 +12390,7 @@ 880059D628EEA55500E87B9B /* View */ = { isa = PBXGroup; children = ( + 882232E82919225E00CBA7B3 /* MarkdownView+load.swift */, 880059DD28EF093400E87B9B /* Slider */, 880059E028EF0A5C00E87B9B /* VotingProgressView.swift */, 880059E228EF128000E87B9B /* ReferendumInfoView.swift */, @@ -15488,6 +15491,7 @@ AE6F7FE42685E812002BBC3E /* ValidatorListFilterViewFactory.swift in Sources */, 842876AA24AE049B00D91AD8 /* SelectionTitleTableViewCell.swift in Sources */, 84CA68DD26BEA60A003B9453 /* ConnectionFactory.swift in Sources */, + 882232E92919226000CBA7B3 /* MarkdownView+load.swift in Sources */, F40966B626B297D6008CD244 /* AnalyticsRewardsPresenter.swift in Sources */, 84A58FD428A05820003F6ABF /* HardwareSigningError.swift in Sources */, F4B39C53273270A300BB6E10 /* AcalaContributionSetupPresenter.swift in Sources */, From f328f0f2251f079dec26a842c6fc00a5c20144c3 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 7 Nov 2022 18:32:11 +0500 Subject: [PATCH 164/229] fix locks --- novawallet.xcodeproj/project.pbxproj | 32 ++- .../Democracy/Democracy+ConstantPath.swift | 4 + .../GovernanceUnlockConfirmViewFactory.swift | 15 +- .../GovernanceUnlockSetupViewFactory.swift | 6 +- .../Model/GovernanceSharedState.swift | 20 +- .../Operation/Gov1LocalMappingFactory.swift | 19 +- .../Gov1OperationFactory+Protocol.swift | 8 +- .../Operation/Gov1OperationFactory.swift | 17 +- .../Locks/Gov1LockStateFactory.swift | 86 ++++++ .../Locks/Gov1UnlockReferendum.swift | 37 +++ .../Locks/Gov2LockStateFactory.swift | 245 +----------------- .../Locks/Gov2UnlockReferendum.swift | 52 ++++ ...lator.swift => GovUnlocksCalculator.swift} | 57 +--- .../Locks/GovernanceLockStateFactory.swift | 240 +++++++++++++++++ .../Locks/GovernanceUnlocksCalculator.swift | 11 +- .../ReferendumVoteConfirmViewFactory.swift | 20 +- .../ReferendumVoteSetupViewFactory.swift | 22 +- .../ReferendumVotersViewFactory.swift | 8 +- .../Referendums/ReferendumsInteractor.swift | 10 +- .../Parent/VoteChildPresenterFactory.swift | 11 - 20 files changed, 552 insertions(+), 368 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/Operation/Locks/Gov1LockStateFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Locks/Gov1UnlockReferendum.swift create mode 100644 novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlockReferendum.swift rename novawallet/Modules/Vote/Governance/Operation/Locks/{Gov2UnlocksCalculator.swift => GovUnlocksCalculator.swift} (85%) create mode 100644 novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceLockStateFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 081f4b3aac..34d7f32f96 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -542,7 +542,7 @@ 84265E062523D7BE005EEE2D /* WalletInputAmountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E052523D7BE005EEE2D /* WalletInputAmountView.swift */; }; 8427495128FEB6E500B2B70B /* GovernanceLockState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8427495028FEB6E500B2B70B /* GovernanceLockState.swift */; }; 8427495328FEB8C800B2B70B /* ReferendumNewVote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8427495228FEB8C800B2B70B /* ReferendumNewVote.swift */; }; - 8427495528FEB92700B2B70B /* Gov2LockStateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8427495428FEB92700B2B70B /* Gov2LockStateFactory.swift */; }; + 8427495528FEB92700B2B70B /* GovernanceLockStateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8427495428FEB92700B2B70B /* GovernanceLockStateFactory.swift */; }; 8427495728FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8427495628FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift */; }; 84274B8127A19AFF00A26657 /* OrmlTokenTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84274B8027A19AFF00A26657 /* OrmlTokenTransfer.swift */; }; 842806F32847A51400702F3A /* AccountDetailsSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842806F22847A51400702F3A /* AccountDetailsSelectionView.swift */; }; @@ -697,7 +697,7 @@ 843461EA290C04C400379936 /* Gov2OperationFactory+Protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */; }; 843461EC290D0D9400379936 /* GovernanceUnlockSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */; }; 843461F5290E4A1C00379936 /* GovernanceUnlocksCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */; }; - 843461F7290E4AF500379936 /* Gov2UnlocksCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */; }; + 843461F7290E4AF500379936 /* GovUnlocksCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F6290E4AF500379936 /* GovUnlocksCalculator.swift */; }; 843461FA290E55D100379936 /* GovernanceUnlocksTestBuilding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461F9290E55D100379936 /* GovernanceUnlocksTestBuilding.swift */; }; 8434C9E425401EF3009E4191 /* TransactionHistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */; }; 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */; }; @@ -969,6 +969,10 @@ 845B080A2918D381005785D3 /* Gov1ExtrinsicFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08092918D381005785D3 /* Gov1ExtrinsicFactory.swift */; }; 845B080D2918D4F8005785D3 /* Democracy+Call.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B080C2918D4F8005785D3 /* Democracy+Call.swift */; }; 845B08102918D65E005785D3 /* GovernanceExtrinsicFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B080F2918D65E005785D3 /* GovernanceExtrinsicFactory.swift */; }; + 845B08132918FF98005785D3 /* Gov2UnlockReferendum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B08122918FF98005785D3 /* Gov2UnlockReferendum.swift */; }; + 845B081529190056005785D3 /* Gov1UnlockReferendum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B081429190056005785D3 /* Gov1UnlockReferendum.swift */; }; + 845B0817291902CF005785D3 /* Gov2LockStateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B0816291902CF005785D3 /* Gov2LockStateFactory.swift */; }; + 845B0819291905CA005785D3 /* Gov1LockStateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B0818291905CA005785D3 /* Gov1LockStateFactory.swift */; }; 845B811228F429BB0040CE84 /* SupportPallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811128F429BB0040CE84 /* SupportPallet.swift */; }; 845B811528F43C350040CE84 /* Treasury.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811428F43C350040CE84 /* Treasury.swift */; }; 845B811728F43C730040CE84 /* TreasuryProposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B811628F43C730040CE84 /* TreasuryProposal.swift */; }; @@ -3507,7 +3511,7 @@ 84265E052523D7BE005EEE2D /* WalletInputAmountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInputAmountView.swift; sourceTree = ""; }; 8427495028FEB6E500B2B70B /* GovernanceLockState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceLockState.swift; sourceTree = ""; }; 8427495228FEB8C800B2B70B /* ReferendumNewVote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumNewVote.swift; sourceTree = ""; }; - 8427495428FEB92700B2B70B /* Gov2LockStateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2LockStateFactory.swift; sourceTree = ""; }; + 8427495428FEB92700B2B70B /* GovernanceLockStateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceLockStateFactory.swift; sourceTree = ""; }; 8427495628FEBFA400B2B70B /* ConvictionVoting+ConstantPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConvictionVoting+ConstantPath.swift"; sourceTree = ""; }; 84274B8027A19AFF00A26657 /* OrmlTokenTransfer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrmlTokenTransfer.swift; sourceTree = ""; }; 842806F22847A51400702F3A /* AccountDetailsSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDetailsSelectionView.swift; sourceTree = ""; }; @@ -3662,7 +3666,7 @@ 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gov2OperationFactory+Protocol.swift"; sourceTree = ""; }; 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSchedule.swift; sourceTree = ""; }; 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlocksCalculator.swift; sourceTree = ""; }; - 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2UnlocksCalculator.swift; sourceTree = ""; }; + 843461F6290E4AF500379936 /* GovUnlocksCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovUnlocksCalculator.swift; sourceTree = ""; }; 843461F9290E55D100379936 /* GovernanceUnlocksTestBuilding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlocksTestBuilding.swift; sourceTree = ""; }; 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryItem.swift; sourceTree = ""; }; 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDTransactionHistoryItem+CoreDataDecodable.swift"; sourceTree = ""; }; @@ -3941,6 +3945,10 @@ 845B080C2918D4F8005785D3 /* Democracy+Call.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Democracy+Call.swift"; sourceTree = ""; }; 845B080F2918D65E005785D3 /* GovernanceExtrinsicFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceExtrinsicFactory.swift; sourceTree = ""; }; 845B08112918E343005785D3 /* SubstrateDataModel4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SubstrateDataModel4.xcdatamodel; sourceTree = ""; }; + 845B08122918FF98005785D3 /* Gov2UnlockReferendum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2UnlockReferendum.swift; sourceTree = ""; }; + 845B081429190056005785D3 /* Gov1UnlockReferendum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1UnlockReferendum.swift; sourceTree = ""; }; + 845B0816291902CF005785D3 /* Gov2LockStateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2LockStateFactory.swift; sourceTree = ""; }; + 845B0818291905CA005785D3 /* Gov1LockStateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov1LockStateFactory.swift; sourceTree = ""; }; 845B811128F429BB0040CE84 /* SupportPallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportPallet.swift; sourceTree = ""; }; 845B811428F43C350040CE84 /* Treasury.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treasury.swift; sourceTree = ""; }; 845B811628F43C730040CE84 /* TreasuryProposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreasuryProposal.swift; sourceTree = ""; }; @@ -7457,9 +7465,13 @@ 843461F1290D370000379936 /* Locks */ = { isa = PBXGroup; children = ( - 8427495428FEB92700B2B70B /* Gov2LockStateFactory.swift */, + 8427495428FEB92700B2B70B /* GovernanceLockStateFactory.swift */, + 845B0816291902CF005785D3 /* Gov2LockStateFactory.swift */, + 845B0818291905CA005785D3 /* Gov1LockStateFactory.swift */, 843461F4290E4A1C00379936 /* GovernanceUnlocksCalculator.swift */, - 843461F6290E4AF500379936 /* Gov2UnlocksCalculator.swift */, + 843461F6290E4AF500379936 /* GovUnlocksCalculator.swift */, + 845B08122918FF98005785D3 /* Gov2UnlockReferendum.swift */, + 845B081429190056005785D3 /* Gov1UnlockReferendum.swift */, ); path = Locks; sourceTree = ""; @@ -14852,6 +14864,7 @@ 88A5317B28B9149600AF18F5 /* UIImage+DrawableIcon.swift in Sources */, 843461F5290E4A1C00379936 /* GovernanceUnlocksCalculator.swift in Sources */, 84C2063A28D1CA90006D0D52 /* YieldBoostCollatorSelectionFactory.swift in Sources */, + 845B08132918FF98005785D3 /* Gov2UnlockReferendum.swift in Sources */, 843612BF278FE59D00DC739E /* DAppOperationConfirmInteractor+Proccessing.swift in Sources */, 842BA36F27B64F1000D31EEF /* DAppListViewModelFactory.swift in Sources */, 84C5ADE42813EBAB006D7388 /* GradientBannerView.swift in Sources */, @@ -16297,7 +16310,7 @@ 8496ADDE276B123200306B24 /* PolkadotExtentionMessage.swift in Sources */, 84A15489262888CA0050D557 /* IdentityOperationFactory.swift in Sources */, 8473D4212657FFFB00B394B2 /* Crowdloan.swift in Sources */, - 843461F7290E4AF500379936 /* Gov2UnlocksCalculator.swift in Sources */, + 843461F7290E4AF500379936 /* GovUnlocksCalculator.swift in Sources */, 849E17E327913220002D1744 /* DAppSearchResult.swift in Sources */, 845B07EB29159190005785D3 /* Democracy.swift in Sources */, 844CB57626FA064700396E13 /* ChainRegistryError.swift in Sources */, @@ -16315,11 +16328,12 @@ 8487583227F06AF300495306 /* AddressScanViewFactory.swift in Sources */, 849632072555CE9D00B8E316 /* ExportSeedData.swift in Sources */, 8485D924277E16C400767243 /* DAppBrowserScriptHandler.swift in Sources */, - 8427495528FEB92700B2B70B /* Gov2LockStateFactory.swift in Sources */, + 8427495528FEB92700B2B70B /* GovernanceLockStateFactory.swift in Sources */, 842BDB2C278C4FFE00AB4B5A /* DAppBrowserAuthorizedState.swift in Sources */, 848919DB26FB663D004DBAD5 /* CrowdloansChainViewModel.swift in Sources */, 842A736D27DB7B5E006EE1EA /* OperationTransferViewModel.swift in Sources */, 842B18022864F9950014CC57 /* CrossChainTransferPresenter.swift in Sources */, + 845B081529190056005785D3 /* Gov1UnlockReferendum.swift in Sources */, 84F3B27427F4130800D64CF5 /* PhishingSites.swift in Sources */, 8430AAF12602306A005B1066 /* BondedState.swift in Sources */, 848F8B1D2863616E00204BC4 /* ChainsStore.swift in Sources */, @@ -16590,6 +16604,7 @@ 640A79BD1335394818E70366 /* WalletHistoryFilterViewController.swift in Sources */, DD090C2ED91726FF7779F6C7 /* WalletHistoryFilterViewFactory.swift in Sources */, 84ED6BE0286900B600B3C558 /* TransferNetworkContainerViewModel.swift in Sources */, + 845B0819291905CA005785D3 /* Gov1LockStateFactory.swift in Sources */, AE6F7FE82685F2F0002BBC3E /* ValidatorListFilterViewModelFactory.swift in Sources */, 84948C38287E0B4F00E6DD3E /* FilterImageProcessor.swift in Sources */, F022F1444E0F75CCA42F4648 /* YourValidatorListProtocols.swift in Sources */, @@ -17176,6 +17191,7 @@ 535E9CD08FCA2DA52D37A134 /* ParitySignerTxQrWireframe.swift in Sources */, 95AF91994555227D52FCDA24 /* ParitySignerTxQrPresenter.swift in Sources */, 211725E26764530359F53A38 /* ParitySignerTxQrInteractor.swift in Sources */, + 845B0817291902CF005785D3 /* Gov2LockStateFactory.swift in Sources */, 41DE96F778AE909978775438 /* ParitySignerTxQrViewController.swift in Sources */, 87F7556E02F6F5BB6F1B1AEA /* ParitySignerTxQrViewLayout.swift in Sources */, 84E90BA128D0B51000529633 /* CheckboxControlView.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift b/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift index e58e200094..205aae39ce 100644 --- a/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift +++ b/novawallet/Common/Substrate/Types/Democracy/Democracy+ConstantPath.swift @@ -5,6 +5,10 @@ extension Democracy { ConstantCodingPath(moduleName: "Democracy", constantName: "VotingPeriod") } + static var voteLockingPeriod: ConstantCodingPath { + ConstantCodingPath(moduleName: "Democracy", constantName: "VoteLockingPeriod") + } + static var enactmentPeriod: ConstantCodingPath { ConstantCodingPath(moduleName: "Democracy", constantName: "EnactmentPeriod") } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift index e98b95111d..37a3628271 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift @@ -15,7 +15,9 @@ struct GovernanceUnlockConfirmViewFactory { let selectedAccount = wallet.fetchMetaChainAccount(for: chain.accountRequest()), let interactor = createInteractor(for: state, chain: chain, selectedAccount: selectedAccount), let assetInfo = chain.utilityAssetDisplayInfo(), - let currencyManager = CurrencyManager.shared else { + let currencyManager = CurrencyManager.shared, + let votingLockId = state.governanceId(for: chain) + else { return nil } @@ -30,7 +32,7 @@ struct GovernanceUnlockConfirmViewFactory { let lockChangeViewModelFactory = ReferendumLockChangeViewModelFactory( assetDisplayInfo: assetInfo, - votingLockId: ConvictionVoting.lockId + votingLockId: votingLockId ) let dataValidatingFactory = GovernanceValidatorFactory( @@ -75,16 +77,13 @@ struct GovernanceUnlockConfirmViewFactory { let connection = state.chainRegistry.getConnection(for: chain.chainId), let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId), let subscriptionFactory = state.subscriptionFactory, + let lockStateFactory = state.locksOperationFactory, + let extrinsicFactory = state.createExtrinsicFactory(for: chain), let blockTimeService = state.blockTimeService, let currencyManager = CurrencyManager.shared else { return nil } - let lockStateFactory = Gov2LockStateFactory( - requestFactory: state.requestFactory, - unlocksCalculator: Gov2UnlocksCalculator() - ) - let operationQueue = OperationManagerFacade.sharedDefaultQueue let extrinsicService = ExtrinsicServiceFactory( @@ -104,7 +103,7 @@ struct GovernanceUnlockConfirmViewFactory { subscriptionFactory: subscriptionFactory, lockStateFactory: lockStateFactory, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, - extrinsicFactory: Gov2ExtrinsicFactory(), + extrinsicFactory: extrinsicFactory, extrinsicService: extrinsicService, signer: signer, priceLocalSubscriptionFactory: PriceProviderFactory.shared, diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift index bd672a0eff..5f7c3b009f 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift @@ -49,15 +49,11 @@ struct GovernanceUnlockSetupViewFactory { let connection = state.chainRegistry.getConnection(for: chain.chainId), let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId), let subscriptionFactory = state.subscriptionFactory, + let lockStateFactory = state.locksOperationFactory, let blockTimeService = state.blockTimeService else { return nil } - let lockStateFactory = Gov2LockStateFactory( - requestFactory: state.requestFactory, - unlocksCalculator: Gov2UnlocksCalculator() - ) - return .init( chain: chain, selectedAccount: selectedAccount, diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index ba907c9c39..b96c2c3beb 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -12,7 +12,8 @@ final class GovernanceSharedState { let operationQueue: OperationQueue private(set) var subscriptionFactory: GovernanceSubscriptionFactoryProtocol? - private(set) var operationFactory: ReferendumsOperationFactoryProtocol? + private(set) var referendumsOperationFactory: ReferendumsOperationFactoryProtocol? + private(set) var locksOperationFactory: GovernanceLockStateFactoryProtocol? private(set) var blockTimeService: BlockTimeEstimationServiceProtocol? init( @@ -53,7 +54,8 @@ final class GovernanceSharedState { func replaceGovernanceFactory(for chain: ChainModel?) { subscriptionFactory = nil - operationFactory = nil + referendumsOperationFactory = nil + locksOperationFactory = nil guard let chain = chain else { return @@ -67,7 +69,7 @@ final class GovernanceSharedState { operationQueue: operationQueue ) - self.operationFactory = operationFactory + referendumsOperationFactory = operationFactory subscriptionFactory = Gov2SubscriptionFactory( chainId: chainId, @@ -75,13 +77,18 @@ final class GovernanceSharedState { chainRegistry: chainRegistry, operationQueue: operationQueue ) + + locksOperationFactory = Gov2LockStateFactory( + requestFactory: requestFactory, + unlocksCalculator: GovUnlocksCalculator() + ) } else if chain.hasGov1 { let operationFactory = Gov1OperationFactory( requestFactory: requestFactory, operationQueue: operationQueue ) - self.operationFactory = operationFactory + referendumsOperationFactory = operationFactory subscriptionFactory = Gov1SubscriptionFactory( chainId: chainId, @@ -89,6 +96,11 @@ final class GovernanceSharedState { chainRegistry: chainRegistry, operationQueue: operationQueue ) + + locksOperationFactory = Gov1LockStateFactory( + requestFactory: requestFactory, + unlocksCalculator: GovUnlocksCalculator() + ) } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift index 0d9e55707b..76b5d36470 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift @@ -38,12 +38,19 @@ final class Gov1LocalMappingFactory { additionalInfo: Gov1OperationFactory.AdditionalInfo ) -> ReferendumLocal { if referendum.approved { - let approved = ReferendumStateLocal.Approved( - since: referendum.end, - whenEnactment: referendum.end + additionalInfo.enactmentPeriod, - deposit: nil - ) - return .init(index: ReferendumIdLocal(index), state: .approved(model: approved), proposer: nil) + let whenEnactment = referendum.end + additionalInfo.enactmentPeriod + + if additionalInfo.block < whenEnactment { + let approved = ReferendumStateLocal.Approved( + since: referendum.end, + whenEnactment: whenEnactment, + deposit: nil + ) + + return .init(index: ReferendumIdLocal(index), state: .approved(model: approved), proposer: nil) + } else { + return .init(index: ReferendumIdLocal(index), state: .executed, proposer: nil) + } } else { let rejected = ReferendumStateLocal.NotApproved( atBlock: referendum.end, diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift index 4d58b44598..42d0fc1c61 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift @@ -59,6 +59,8 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { blockHash: blockHash ) + additionalInfoWrapper.addDependency(operations: [codingFactoryOperation]) + let referendumOperation = ClosureOperation<[ReferendumIndexKey: Democracy.ReferendumInfo]> { let referendumIndexKey = ReferendumIndexKey(referendumIndex: Referenda.ReferendumIndex(index)) return [referendumIndexKey: remoteReferendum] @@ -151,7 +153,11 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) } - func fetchVotersWrapper(for referendumIndex: ReferendumIdLocal, from connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol) -> CompoundOperationWrapper<[ReferendumVoterLocal]> { + func fetchVotersWrapper( + for referendumIndex: ReferendumIdLocal, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol + ) -> CompoundOperationWrapper<[ReferendumVoterLocal]> { let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() let request = UnkeyedRemoteStorageRequest(storagePath: Democracy.votingOf) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift index 4ea2c81a45..6c1fb849bc 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift @@ -11,6 +11,7 @@ final class Gov1OperationFactory { let votingPeriod: UInt32 let enactmentPeriod: UInt32 let totalIssuance: BigUInt + let block: BlockNumber } let requestFactory: StorageRequestFactoryProtocol @@ -52,23 +53,35 @@ final class Gov1OperationFactory { at: blockHash ) + let blockNumberWrapper: CompoundOperationWrapper>> = + requestFactory.queryItem( + engine: connection, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: .blockNumber, + at: blockHash + ) + let mapOperation = ClosureOperation { let votingPeriod = try votingPeriodOperation.extractNoCancellableResultData() let totalIssuance = try totalIssuanceWrapper.targetOperation.extractNoCancellableResultData().value let enactmentPeriod = try enactmentPeriodOperation.extractNoCancellableResultData() + let block = try blockNumberWrapper.targetOperation.extractNoCancellableResultData().value return .init( votingPeriod: votingPeriod, enactmentPeriod: enactmentPeriod, - totalIssuance: totalIssuance?.value ?? 0 + totalIssuance: totalIssuance?.value ?? 0, + block: block?.value ?? 0 ) } mapOperation.addDependency(votingPeriodOperation) mapOperation.addDependency(totalIssuanceWrapper.targetOperation) mapOperation.addDependency(enactmentPeriodOperation) + mapOperation.addDependency(blockNumberWrapper.targetOperation) - let dependencies = [votingPeriodOperation, enactmentPeriodOperation] + totalIssuanceWrapper.allOperations + let dependencies = [votingPeriodOperation, enactmentPeriodOperation] + totalIssuanceWrapper.allOperations + + blockNumberWrapper.allOperations return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov1LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov1LockStateFactory.swift new file mode 100644 index 0000000000..9374be0cd2 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov1LockStateFactory.swift @@ -0,0 +1,86 @@ +import Foundation +import RobinHood +import SubstrateSdk + +final class Gov1LockStateFactory: GovernanceLockStateFactory { + override func createReferendumsWrapper( + for referendumIds: Set, + connection: JSONRPCEngine, + codingFactoryOperation: BaseOperation, + blockHash: Data? + ) -> CompoundOperationWrapper<[ReferendumIdLocal: GovUnlockReferendumProtocol]> { + let remoteIndexes = Array(referendumIds.map { StringScaleMapper(value: $0) }) + + let wrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( + engine: connection, + keyParams: { remoteIndexes }, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: Democracy.referendumInfo, + at: blockHash + ) + + let mappingOperation = ClosureOperation<[ReferendumIdLocal: GovUnlockReferendumProtocol]> { + let responses = try wrapper.targetOperation.extractNoCancellableResultData() + + let initAccum = [ReferendumIdLocal: GovUnlockReferendumProtocol]() + return zip(remoteIndexes, responses).reduce(into: initAccum) { accum, pair in + accum[pair.0.value] = pair.1.value.map { Gov1UnlockReferendum(referendum: $0) } + } + } + + mappingOperation.addDependency(wrapper.targetOperation) + + return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: wrapper.allOperations) + } + + override func createAdditionalInfoWrapper( + dependingOn codingFactoryOperation: BaseOperation + ) -> CompoundOperationWrapper { + let lockingPeriodOperation = PrimitiveConstantOperation(path: Democracy.voteLockingPeriod) + + lockingPeriodOperation.configurationBlock = { + do { + lockingPeriodOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + lockingPeriodOperation.result = .failure(error) + } + } + + lockingPeriodOperation.configurationBlock = { + do { + lockingPeriodOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + lockingPeriodOperation.result = .failure(error) + } + } + + let votingPeriodOperation = PrimitiveConstantOperation(path: Democracy.votingPeriod) + + votingPeriodOperation.configurationBlock = { + do { + votingPeriodOperation.codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + } catch { + votingPeriodOperation.result = .failure(error) + } + } + + let mappingOperation = ClosureOperation { + let lockingPeriod = try lockingPeriodOperation.extractNoCancellableResultData() + let votingPeriod = try votingPeriodOperation.extractNoCancellableResultData() + + return GovUnlockCalculationInfo( + decisionPeriods: [Gov1OperationFactory.trackId: votingPeriod], + undecidingTimeout: 0, + voteLockingPeriod: lockingPeriod + ) + } + + mappingOperation.addDependency(lockingPeriodOperation) + mappingOperation.addDependency(votingPeriodOperation) + + return CompoundOperationWrapper( + targetOperation: mappingOperation, + dependencies: [lockingPeriodOperation, votingPeriodOperation] + ) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov1UnlockReferendum.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov1UnlockReferendum.swift new file mode 100644 index 0000000000..43bbd45530 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov1UnlockReferendum.swift @@ -0,0 +1,37 @@ +import Foundation + +final class Gov1UnlockReferendum { + let referendum: Democracy.ReferendumInfo + + init(referendum: Democracy.ReferendumInfo) { + self.referendum = referendum + } +} + +extension Gov1UnlockReferendum: GovUnlockReferendumProtocol { + func estimateVoteLockingPeriod( + for accountVote: ReferendumAccountVoteLocal, + additionalInfo: GovUnlockCalculationInfo + ) throws -> BlockNumber? { + let conviction = accountVote.convictionValue + + guard let convictionPeriod = conviction.conviction(for: additionalInfo.voteLockingPeriod) else { + throw CommonError.dataCorruption + } + + switch referendum { + case let .ongoing(status): + return status.end + convictionPeriod + case let .finished(status): + if status.approved, accountVote.hasAyeVotes { + return status.end + convictionPeriod + } else if !status.approved, accountVote.hasNayVotes { + return status.end + convictionPeriod + } else { + return nil + } + case .unknown: + return nil + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift index bdade09a63..1126c06e4a 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2LockStateFactory.swift @@ -1,39 +1,14 @@ import Foundation import RobinHood import SubstrateSdk -import BigInt -/** - * Class that calculates: - * Locked amount diff - maximum amount of tokens locked before vote is applied and after - * Locked period diff - period of time needed to unlock all the tokens before vote is applied and after. - * - * Locked amount calculation assumes that no unlocks can happen during - * voting (event if voting for the same referendum). So the diff may not decrease. - * - * Locked period is calculated first by maximizing estimation for unlock block of votes (only nonzero amount). - * And then maximizing result between maximum period for votes and prior locks - * (taking into account both casting votes and delegations). - * - * Note that locked period calculation uses an estimation that takes maximum time when voting for particular referendum - * may end. - */ - -final class Gov2LockStateFactory { - let requestFactory: StorageRequestFactoryProtocol - let unlocksCalculator: GovernanceUnlockCalculatorProtocol - - init(requestFactory: StorageRequestFactoryProtocol, unlocksCalculator: GovernanceUnlockCalculatorProtocol) { - self.requestFactory = requestFactory - self.unlocksCalculator = unlocksCalculator - } - - func createReferendumsWrapper( +final class Gov2LockStateFactory: GovernanceLockStateFactory { + override func createReferendumsWrapper( for referendumIds: Set, connection: JSONRPCEngine, codingFactoryOperation: BaseOperation, blockHash: Data? - ) -> CompoundOperationWrapper<[ReferendumIdLocal: ReferendumInfo]> { + ) -> CompoundOperationWrapper<[ReferendumIdLocal: GovUnlockReferendumProtocol]> { let remoteIndexes = Array(referendumIds.map { StringScaleMapper(value: $0) }) let wrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( @@ -44,11 +19,12 @@ final class Gov2LockStateFactory { at: blockHash ) - let mappingOperation = ClosureOperation<[ReferendumIdLocal: ReferendumInfo]> { + let mappingOperation = ClosureOperation<[ReferendumIdLocal: GovUnlockReferendumProtocol]> { let responses = try wrapper.targetOperation.extractNoCancellableResultData() - return zip(remoteIndexes, responses).reduce(into: [ReferendumIdLocal: ReferendumInfo]()) { accum, pair in - accum[pair.0.value] = pair.1.value + let initAccum = [ReferendumIdLocal: GovUnlockReferendumProtocol]() + return zip(remoteIndexes, responses).reduce(into: initAccum) { accum, pair in + accum[pair.0.value] = pair.1.value.map { Gov2UnlockReferendum(referendumInfo: $0) } } } @@ -57,7 +33,7 @@ final class Gov2LockStateFactory { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: wrapper.allOperations) } - func createAdditionalInfoWrapper( + override func createAdditionalInfoWrapper( dependingOn codingFactoryOperation: BaseOperation ) -> CompoundOperationWrapper { let tracksOperation = StorageConstantOperation<[Referenda.Track]>(path: Referenda.tracks) @@ -94,16 +70,16 @@ final class Gov2LockStateFactory { fetchOperations.forEach { $0.addDependency(codingFactoryOperation) } let mappingOperation = ClosureOperation { - let tracks = try tracksOperation.extractNoCancellableResultData().reduce( - into: [Referenda.TrackId: Referenda.TrackInfo]() - ) { $0[$1.trackId] = $1.info } + let decisionPeriods = try tracksOperation.extractNoCancellableResultData().reduce( + into: [Referenda.TrackId: Moment]() + ) { $0[$1.trackId] = $1.info.decisionPeriod } let undecidingTimeout = try undecidingTimeoutOperation.extractNoCancellableResultData() let lockingPeriod = try lockingPeriodOperation.extractNoCancellableResultData() return GovUnlockCalculationInfo( - tracks: tracks, + decisionPeriods: decisionPeriods, undecidingTimeout: undecidingTimeout, voteLockingPeriod: lockingPeriod ) @@ -113,201 +89,4 @@ final class Gov2LockStateFactory { return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: fetchOperations) } - - func calculatePriorLockMax(from trackVotes: ReferendumTracksVotingDistribution) -> BlockNumber? { - let optCastingMax = trackVotes.votes.priorLocks.values - .filter { $0.exists } - .map(\.unlockAt) - .max() - - let optDelegatingMax = trackVotes.votes.delegatings.values - .compactMap { $0.prior.exists ? $0.prior.unlockAt : nil } - .max() - - if let castingMax = optCastingMax, let delegatingMax = optDelegatingMax { - return max(castingMax, delegatingMax) - } else if let castingMax = optCastingMax { - return castingMax - } else { - return optDelegatingMax - } - } - - func calculateMaxLock( - for referendums: [ReferendumIdLocal: ReferendumInfo], - trackVotes: ReferendumTracksVotingDistribution, - additions: GovUnlockCalculationInfo - ) -> BlockNumber? { - let optVotesMax: Moment? = referendums.compactMap { referendumKeyValue in - let referendumIndex = referendumKeyValue.key - let referendum = referendumKeyValue.value - - let accountVoting = trackVotes.votes - guard let vote = accountVoting.votes[referendumIndex] else { - return nil - } - - return try? unlocksCalculator.estimateVoteLockingPeriod( - for: referendum, - accountVote: vote, - additionalInfo: additions - ) - }.max() - - let optPriorMax = calculatePriorLockMax(from: trackVotes) - - if let votesMax = optVotesMax, let priorMax = optPriorMax { - return max(votesMax, priorMax) - } else if let votesMax = optVotesMax { - return votesMax - } else { - return optPriorMax - } - } - - func createStateDiffOperation( - for trackVotes: ReferendumTracksVotingDistribution, - newVote: ReferendumNewVote?, - referendumsOperation: BaseOperation<[ReferendumIdLocal: ReferendumInfo]>, - additionalInfoOperation: BaseOperation - ) -> BaseOperation { - ClosureOperation { - let referendums = try referendumsOperation.extractNoCancellableResultData() - let additions = try additionalInfoOperation.extractNoCancellableResultData() - - let oldAmount = trackVotes.trackLocks.map(\.amount).max() ?? 0 - - let oldPeriod: Moment? = self.calculateMaxLock( - for: referendums, - trackVotes: trackVotes, - additions: additions - ) - - let oldState = GovernanceLockState(maxLockedAmount: oldAmount, lockedUntil: oldPeriod) - - let newState: GovernanceLockState? - - if let newVote = newVote { - let newAmount = max(oldAmount, newVote.voteAction.amount) - - // as we replacing the vote we can immediately claim previos one so don't take into account - let filteredReferendums = referendums.filter { $0.key != newVote.index } - - let periodWithoutReferendum = self.calculateMaxLock( - for: filteredReferendums, - trackVotes: trackVotes, - additions: additions - ) - - let newPeriod: Moment? - - if - let referendum = referendums[newVote.index], - let periodWithNewVote = try? self.unlocksCalculator.estimateVoteLockingPeriod( - for: referendum, - accountVote: newVote.toAccountVote(), - additionalInfo: additions - ) { - newPeriod = periodWithoutReferendum.flatMap { max(periodWithNewVote, $0) } ?? periodWithNewVote - } else { - newPeriod = periodWithoutReferendum - } - - newState = GovernanceLockState(maxLockedAmount: newAmount, lockedUntil: newPeriod) - } else { - newState = nil - } - - return GovernanceLockStateDiff(before: oldState, vote: newVote, after: newState) - } - } -} - -extension Gov2LockStateFactory: GovernanceLockStateFactoryProtocol { - func calculateLockStateDiff( - for trackVotes: ReferendumTracksVotingDistribution, - newVote: ReferendumNewVote?, - from connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol, - blockHash: Data? - ) -> CompoundOperationWrapper { - let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - - let accountVoting = trackVotes.votes - var allReferendumIds = Set(accountVoting.votes.keys) - - if let newVoteIndex = newVote?.index { - allReferendumIds.insert(newVoteIndex) - } - - let referendumsWrapper = createReferendumsWrapper( - for: allReferendumIds, - connection: connection, - codingFactoryOperation: codingFactoryOperation, - blockHash: blockHash - ) - - let additionalInfoWrapper = createAdditionalInfoWrapper(dependingOn: codingFactoryOperation) - - referendumsWrapper.addDependency(operations: [codingFactoryOperation]) - additionalInfoWrapper.addDependency(operations: [codingFactoryOperation]) - - let calculationOperation = createStateDiffOperation( - for: trackVotes, - newVote: newVote, - referendumsOperation: referendumsWrapper.targetOperation, - additionalInfoOperation: additionalInfoWrapper.targetOperation - ) - - calculationOperation.addDependency(referendumsWrapper.targetOperation) - calculationOperation.addDependency(additionalInfoWrapper.targetOperation) - - let dependencies = [codingFactoryOperation] + referendumsWrapper.allOperations + - additionalInfoWrapper.allOperations - - return CompoundOperationWrapper(targetOperation: calculationOperation, dependencies: dependencies) - } - - func buildUnlockScheduleWrapper( - for tracksVoting: ReferendumTracksVotingDistribution, - from connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol, - blockHash: Data? - ) -> CompoundOperationWrapper { - let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - - let accountVoting = tracksVoting.votes - let allReferendumIds = Set(accountVoting.votes.keys) - - let referendumsWrapper = createReferendumsWrapper( - for: allReferendumIds, - connection: connection, - codingFactoryOperation: codingFactoryOperation, - blockHash: blockHash - ) - - let additionalInfoWrapper = createAdditionalInfoWrapper(dependingOn: codingFactoryOperation) - - referendumsWrapper.addDependency(operations: [codingFactoryOperation]) - additionalInfoWrapper.addDependency(operations: [codingFactoryOperation]) - - let scheduleOperation = ClosureOperation { - let referendums = try referendumsWrapper.targetOperation.extractNoCancellableResultData() - let additions = try additionalInfoWrapper.targetOperation.extractNoCancellableResultData() - - return self.unlocksCalculator.createUnlocksSchedule( - for: tracksVoting, - referendums: referendums, - additionalInfo: additions - ) - } - - scheduleOperation.addDependency(referendumsWrapper.targetOperation) - scheduleOperation.addDependency(additionalInfoWrapper.targetOperation) - - let dependencies = [codingFactoryOperation] + referendumsWrapper.allOperations + - additionalInfoWrapper.allOperations - - return CompoundOperationWrapper(targetOperation: scheduleOperation, dependencies: dependencies) - } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlockReferendum.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlockReferendum.swift new file mode 100644 index 0000000000..2209ab9d59 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlockReferendum.swift @@ -0,0 +1,52 @@ +import Foundation + +final class Gov2UnlockReferendum { + let referendumInfo: ReferendumInfo + + init(referendumInfo: ReferendumInfo) { + self.referendumInfo = referendumInfo + } +} + +extension Gov2UnlockReferendum: GovUnlockReferendumProtocol { + func estimateVoteLockingPeriod( + for accountVote: ReferendumAccountVoteLocal, + additionalInfo: GovUnlockCalculationInfo + ) throws -> BlockNumber? { + let conviction = accountVote.convictionValue + + guard let convictionPeriod = conviction.conviction(for: additionalInfo.voteLockingPeriod) else { + throw CommonError.dataCorruption + } + + switch referendumInfo { + case let .ongoing(ongoingStatus): + guard let decisionPeriod = additionalInfo.decisionPeriods[ongoingStatus.track] else { + return nil + } + + if let decidingSince = ongoingStatus.deciding?.since { + return decidingSince + decisionPeriod + convictionPeriod + } else { + return ongoingStatus.submitted + additionalInfo.undecidingTimeout + + decisionPeriod + convictionPeriod + } + case let .approved(completedStatus): + if accountVote.hasAyeVotes { + return completedStatus.since + convictionPeriod + } else { + return nil + } + case let .rejected(completedStatus): + if accountVote.hasNayVotes { + return completedStatus.since + convictionPeriod + } else { + return nil + } + case .killed, .timedOut, .cancelled: + return nil + case .unknown: + throw CommonError.dataCorruption + } + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/GovUnlocksCalculator.swift similarity index 85% rename from novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift rename to novawallet/Modules/Vote/Governance/Operation/Locks/GovUnlocksCalculator.swift index e7e24fc536..5e681ee501 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Locks/Gov2UnlocksCalculator.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/GovUnlocksCalculator.swift @@ -43,10 +43,10 @@ import BigInt * 4. To find which unlocks are claimable one should call [GovernanceUnlockSchedule.availableItem(at:)] * function by providing current block number; */ -final class Gov2UnlocksCalculator { +final class GovUnlocksCalculator { private func createUnlocksFromVotes( _ votes: [ReferendumIdLocal: ReferendumAccountVoteLocal], - referendums: [ReferendumIdLocal: ReferendumInfo], + referendums: [ReferendumIdLocal: GovUnlockReferendumProtocol], tracks: [ReferendumIdLocal: TrackIdLocal], additionalInfo: GovUnlockCalculationInfo ) -> [TrackIdLocal: [GovernanceUnlockSchedule.Item]] { @@ -61,9 +61,8 @@ final class Gov2UnlocksCalculator { } do { - let unlockAt = try estimateVoteLockingPeriod( - for: referendum, - accountVote: vote, + let unlockAt = try referendum.estimateVoteLockingPeriod( + for: vote, additionalInfo: additionalInfo ) ?? 0 @@ -173,7 +172,7 @@ final class Gov2UnlocksCalculator { private func createVotingUnlocks( for tracksVoting: ReferendumTracksVotingDistribution, - referendums: [ReferendumIdLocal: ReferendumInfo], + referendums: [ReferendumIdLocal: GovUnlockReferendumProtocol], additionalInfo: GovUnlockCalculationInfo ) -> [TrackIdLocal: [GovernanceUnlockSchedule.Item]] { let tracks = tracksVoting.votes.tracksByReferendums() @@ -271,52 +270,10 @@ final class Gov2UnlocksCalculator { } } -extension Gov2UnlocksCalculator: GovernanceUnlockCalculatorProtocol { - func estimateVoteLockingPeriod( - for referendumInfo: ReferendumInfo, - accountVote: ReferendumAccountVoteLocal, - additionalInfo: GovUnlockCalculationInfo - ) throws -> BlockNumber? { - let conviction = accountVote.convictionValue - - guard let convictionPeriod = conviction.conviction(for: additionalInfo.voteLockingPeriod) else { - throw CommonError.dataCorruption - } - - switch referendumInfo { - case let .ongoing(ongoingStatus): - guard let track = additionalInfo.tracks[ongoingStatus.track] else { - return nil - } - - if let decidingSince = ongoingStatus.deciding?.since { - return decidingSince + track.decisionPeriod + convictionPeriod - } else { - return ongoingStatus.submitted + additionalInfo.undecidingTimeout + - track.decisionPeriod + convictionPeriod - } - case let .approved(completedStatus): - if accountVote.ayes > 0 { - return completedStatus.since + convictionPeriod - } else { - return nil - } - case let .rejected(completedStatus): - if accountVote.nays > 0 { - return completedStatus.since + convictionPeriod - } else { - return nil - } - case .killed, .timedOut, .cancelled: - return nil - case .unknown: - throw CommonError.dataCorruption - } - } - +extension GovUnlocksCalculator: GovernanceUnlockCalculatorProtocol { func createUnlocksSchedule( for tracksVoting: ReferendumTracksVotingDistribution, - referendums: [ReferendumIdLocal: ReferendumInfo], + referendums: [ReferendumIdLocal: GovUnlockReferendumProtocol], additionalInfo: GovUnlockCalculationInfo ) -> GovernanceUnlockSchedule { let unlocks = createVotingUnlocks( diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceLockStateFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceLockStateFactory.swift new file mode 100644 index 0000000000..dffff42abe --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceLockStateFactory.swift @@ -0,0 +1,240 @@ +import Foundation +import RobinHood +import SubstrateSdk +import BigInt + +/** + * Class that calculates: + * Locked amount diff - maximum amount of tokens locked before vote is applied and after + * Locked period diff - period of time needed to unlock all the tokens before vote is applied and after. + * + * Locked amount calculation assumes that no unlocks can happen during + * voting (event if voting for the same referendum). So the diff may not decrease. + * + * Locked period is calculated first by maximizing estimation for unlock block of votes (only nonzero amount). + * And then maximizing result between maximum period for votes and prior locks + * (taking into account both casting votes and delegations). + * + * Note that locked period calculation uses an estimation that takes maximum time when voting for particular referendum + * may end. + */ + +class GovernanceLockStateFactory { + let requestFactory: StorageRequestFactoryProtocol + let unlocksCalculator: GovernanceUnlockCalculatorProtocol + + init(requestFactory: StorageRequestFactoryProtocol, unlocksCalculator: GovernanceUnlockCalculatorProtocol) { + self.requestFactory = requestFactory + self.unlocksCalculator = unlocksCalculator + } + + func createReferendumsWrapper( + for _: Set, + connection _: JSONRPCEngine, + codingFactoryOperation _: BaseOperation, + blockHash _: Data? + ) -> CompoundOperationWrapper<[ReferendumIdLocal: GovUnlockReferendumProtocol]> { + fatalError("Child class must implement this method") + } + + func createAdditionalInfoWrapper( + dependingOn _: BaseOperation + ) -> CompoundOperationWrapper { + fatalError("Child class must implement this method") + } + + func calculatePriorLockMax(from trackVotes: ReferendumTracksVotingDistribution) -> BlockNumber? { + let optCastingMax = trackVotes.votes.priorLocks.values + .filter { $0.exists } + .map(\.unlockAt) + .max() + + let optDelegatingMax = trackVotes.votes.delegatings.values + .compactMap { $0.prior.exists ? $0.prior.unlockAt : nil } + .max() + + if let castingMax = optCastingMax, let delegatingMax = optDelegatingMax { + return max(castingMax, delegatingMax) + } else if let castingMax = optCastingMax { + return castingMax + } else { + return optDelegatingMax + } + } + + func calculateMaxLock( + for referendums: [ReferendumIdLocal: GovUnlockReferendumProtocol], + trackVotes: ReferendumTracksVotingDistribution, + additions: GovUnlockCalculationInfo + ) -> BlockNumber? { + let optVotesMax: Moment? = referendums.compactMap { referendumKeyValue in + let referendumIndex = referendumKeyValue.key + let referendum = referendumKeyValue.value + + let accountVoting = trackVotes.votes + guard let vote = accountVoting.votes[referendumIndex] else { + return nil + } + + return try? referendum.estimateVoteLockingPeriod( + for: vote, + additionalInfo: additions + ) + }.max() + + let optPriorMax = calculatePriorLockMax(from: trackVotes) + + if let votesMax = optVotesMax, let priorMax = optPriorMax { + return max(votesMax, priorMax) + } else if let votesMax = optVotesMax { + return votesMax + } else { + return optPriorMax + } + } + + func createStateDiffOperation( + for trackVotes: ReferendumTracksVotingDistribution, + newVote: ReferendumNewVote?, + referendumsOperation: BaseOperation<[ReferendumIdLocal: GovUnlockReferendumProtocol]>, + additionalInfoOperation: BaseOperation + ) -> BaseOperation { + ClosureOperation { + let referendums = try referendumsOperation.extractNoCancellableResultData() + let additions = try additionalInfoOperation.extractNoCancellableResultData() + + let oldAmount = trackVotes.trackLocks.map(\.amount).max() ?? 0 + + let oldPeriod: Moment? = self.calculateMaxLock( + for: referendums, + trackVotes: trackVotes, + additions: additions + ) + + let oldState = GovernanceLockState(maxLockedAmount: oldAmount, lockedUntil: oldPeriod) + + let newState: GovernanceLockState? + + if let newVote = newVote { + let newAmount = max(oldAmount, newVote.voteAction.amount) + + // as we replacing the vote we can immediately claim previos one so don't take into account + let filteredReferendums = referendums.filter { $0.key != newVote.index } + + let periodWithoutReferendum = self.calculateMaxLock( + for: filteredReferendums, + trackVotes: trackVotes, + additions: additions + ) + + let newPeriod: Moment? + + if + let referendum = referendums[newVote.index], + let periodWithNewVote = try? referendum.estimateVoteLockingPeriod( + for: newVote.toAccountVote(), + additionalInfo: additions + ) { + newPeriod = periodWithoutReferendum.flatMap { max(periodWithNewVote, $0) } ?? periodWithNewVote + } else { + newPeriod = periodWithoutReferendum + } + + newState = GovernanceLockState(maxLockedAmount: newAmount, lockedUntil: newPeriod) + } else { + newState = nil + } + + return GovernanceLockStateDiff(before: oldState, vote: newVote, after: newState) + } + } +} + +extension GovernanceLockStateFactory: GovernanceLockStateFactoryProtocol { + func calculateLockStateDiff( + for trackVotes: ReferendumTracksVotingDistribution, + newVote: ReferendumNewVote?, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let accountVoting = trackVotes.votes + var allReferendumIds = Set(accountVoting.votes.keys) + + if let newVoteIndex = newVote?.index { + allReferendumIds.insert(newVoteIndex) + } + + let referendumsWrapper = createReferendumsWrapper( + for: allReferendumIds, + connection: connection, + codingFactoryOperation: codingFactoryOperation, + blockHash: blockHash + ) + + let additionalInfoWrapper = createAdditionalInfoWrapper(dependingOn: codingFactoryOperation) + + referendumsWrapper.addDependency(operations: [codingFactoryOperation]) + additionalInfoWrapper.addDependency(operations: [codingFactoryOperation]) + + let calculationOperation = createStateDiffOperation( + for: trackVotes, + newVote: newVote, + referendumsOperation: referendumsWrapper.targetOperation, + additionalInfoOperation: additionalInfoWrapper.targetOperation + ) + + calculationOperation.addDependency(referendumsWrapper.targetOperation) + calculationOperation.addDependency(additionalInfoWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + referendumsWrapper.allOperations + + additionalInfoWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: calculationOperation, dependencies: dependencies) + } + + func buildUnlockScheduleWrapper( + for tracksVoting: ReferendumTracksVotingDistribution, + from connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper { + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let accountVoting = tracksVoting.votes + let allReferendumIds = Set(accountVoting.votes.keys) + + let referendumsWrapper = createReferendumsWrapper( + for: allReferendumIds, + connection: connection, + codingFactoryOperation: codingFactoryOperation, + blockHash: blockHash + ) + + let additionalInfoWrapper = createAdditionalInfoWrapper(dependingOn: codingFactoryOperation) + + referendumsWrapper.addDependency(operations: [codingFactoryOperation]) + additionalInfoWrapper.addDependency(operations: [codingFactoryOperation]) + + let scheduleOperation = ClosureOperation { + let referendums = try referendumsWrapper.targetOperation.extractNoCancellableResultData() + let additions = try additionalInfoWrapper.targetOperation.extractNoCancellableResultData() + + return self.unlocksCalculator.createUnlocksSchedule( + for: tracksVoting, + referendums: referendums, + additionalInfo: additions + ) + } + + scheduleOperation.addDependency(referendumsWrapper.targetOperation) + scheduleOperation.addDependency(additionalInfoWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + referendumsWrapper.allOperations + + additionalInfoWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: scheduleOperation, dependencies: dependencies) + } +} diff --git a/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceUnlocksCalculator.swift b/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceUnlocksCalculator.swift index f21c886f9f..224828de57 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceUnlocksCalculator.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Locks/GovernanceUnlocksCalculator.swift @@ -1,21 +1,22 @@ import Foundation struct GovUnlockCalculationInfo { - let tracks: [Referenda.TrackId: Referenda.TrackInfo] + let decisionPeriods: [Referenda.TrackId: Moment] let undecidingTimeout: Moment let voteLockingPeriod: Moment } -protocol GovernanceUnlockCalculatorProtocol { +protocol GovUnlockReferendumProtocol { func estimateVoteLockingPeriod( - for referendumInfo: ReferendumInfo, - accountVote: ReferendumAccountVoteLocal, + for accountVote: ReferendumAccountVoteLocal, additionalInfo: GovUnlockCalculationInfo ) throws -> BlockNumber? +} +protocol GovernanceUnlockCalculatorProtocol { func createUnlocksSchedule( for tracksVoting: ReferendumTracksVotingDistribution, - referendums: [ReferendumIdLocal: ReferendumInfo], + referendums: [ReferendumIdLocal: GovUnlockReferendumProtocol], additionalInfo: GovUnlockCalculationInfo ) -> GovernanceUnlockSchedule } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift index c8498cf99e..d5e616793c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -19,7 +19,9 @@ struct ReferendumVoteConfirmViewFactory { let assetDisplayInfo = chain.utilityAsset()?.displayInfo(with: chain.icon), let selectedAccount = SelectedWalletSettings.shared.value?.fetchMetaChainAccount( for: chain.accountRequest() - ) else { + ), + let votingLockId = state.governanceId(for: chain) + else { return nil } @@ -34,7 +36,7 @@ struct ReferendumVoteConfirmViewFactory { let lockChangeViewModelFactory = ReferendumLockChangeViewModelFactory( assetDisplayInfo: assetDisplayInfo, - votingLockId: ConvictionVoting.lockId + votingLockId: votingLockId ) let referendumStringsViewModelFactory = ReferendumDisplayStringFactory() @@ -84,6 +86,8 @@ struct ReferendumVoteConfirmViewFactory { let chain = state.settings.value, let selectedAccount = wallet?.fetchMetaChainAccount(for: chain.accountRequest()), let subscriptionFactory = state.subscriptionFactory, + let lockStateFactory = state.locksOperationFactory, + let extrinsicFactory = state.createExtrinsicFactory(for: chain), let blockTimeService = state.blockTimeService else { return nil @@ -98,16 +102,6 @@ struct ReferendumVoteConfirmViewFactory { let operationQueue = OperationManagerFacade.sharedDefaultQueue let operationManager = OperationManager(operationQueue: operationQueue) - let requestFactory = StorageRequestFactory( - remoteFactory: StorageKeyFactory(), - operationManager: operationManager - ) - - let lockStateFactory = Gov2LockStateFactory( - requestFactory: requestFactory, - unlocksCalculator: Gov2UnlocksCalculator() - ) - let extrinsicService = ExtrinsicServiceFactory( runtimeRegistry: runtimeProvider, engine: connection, @@ -131,7 +125,7 @@ struct ReferendumVoteConfirmViewFactory { connection: connection, runtimeProvider: runtimeProvider, currencyManager: currencyManager, - extrinsicFactory: Gov2ExtrinsicFactory(), + extrinsicFactory: extrinsicFactory, extrinsicService: extrinsicService, signer: signer, feeProxy: ExtrinsicFeeProxy(), diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index 23d8fc9b57..1e4eb5ca72 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -9,7 +9,6 @@ struct ReferendumVoteSetupViewFactory { referendum: ReferendumIdLocal ) -> ReferendumVoteSetupViewProtocol? { guard - let chain = state.settings.value, let currencyManager = CurrencyManager.shared, let interactor = createInteractor( for: state, @@ -33,7 +32,7 @@ struct ReferendumVoteSetupViewFactory { wireframe: wireframe, dataValidatingFactory: dataValidatingFactory, referendum: referendum, - chain: chain + state: state ) else { return nil } @@ -55,11 +54,14 @@ struct ReferendumVoteSetupViewFactory { wireframe: ReferendumVoteSetupWireframeProtocol, dataValidatingFactory: GovernanceValidatorFactoryProtocol, referendum: ReferendumIdLocal, - chain: ChainModel + state: GovernanceSharedState ) -> ReferendumVoteSetupPresenter? { guard + let chain = state.settings.value, let assetDisplayInfo = chain.utilityAssetDisplayInfo(), - let currencyManager = CurrencyManager.shared else { + let currencyManager = CurrencyManager.shared, + let votingLockId = state.governanceId(for: chain) + else { return nil } @@ -73,7 +75,7 @@ struct ReferendumVoteSetupViewFactory { let lockChangeViewModelFactory = ReferendumLockChangeViewModelFactory( assetDisplayInfo: assetDisplayInfo, - votingLockId: ConvictionVoting.lockId + votingLockId: votingLockId ) let referendumStringsViewModelFactory = ReferendumDisplayStringFactory() @@ -105,6 +107,8 @@ struct ReferendumVoteSetupViewFactory { let chain = state.settings.value, let selectedAccount = wallet?.fetchMetaChainAccount(for: chain.accountRequest()), let subscriptionFactory = state.subscriptionFactory, + let lockStateFactory = state.locksOperationFactory, + let extrinsicFactory = state.createExtrinsicFactory(for: chain), let blockTimeService = state.blockTimeService else { return nil @@ -119,12 +123,6 @@ struct ReferendumVoteSetupViewFactory { let operationQueue = OperationManagerFacade.sharedDefaultQueue let operationManager = OperationManager(operationQueue: operationQueue) - let storageFactory = StorageKeyFactory() - let requestFactory = StorageRequestFactory(remoteFactory: storageFactory, operationManager: operationManager) - - let calculator = Gov2UnlocksCalculator() - let lockStateFactory = Gov2LockStateFactory(requestFactory: requestFactory, unlocksCalculator: calculator) - let extrinsicService = ExtrinsicServiceFactory( runtimeRegistry: runtimeProvider, engine: connection, @@ -143,7 +141,7 @@ struct ReferendumVoteSetupViewFactory { connection: connection, runtimeProvider: runtimeProvider, currencyManager: currencyManager, - extrinsicFactory: Gov2ExtrinsicFactory(), + extrinsicFactory: extrinsicFactory, extrinsicService: extrinsicService, feeProxy: ExtrinsicFeeProxy(), lockStateFactory: lockStateFactory, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift index dd30e7f082..2195702a7c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift @@ -60,7 +60,8 @@ struct ReferendumVotersViewFactory { guard let connection = chainRegistry.getConnection(for: chain.chainId), - let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId), + let referendumsOperationFactory = state.referendumsOperationFactory else { return nil } @@ -71,11 +72,6 @@ struct ReferendumVotersViewFactory { operationManager: OperationManager(operationQueue: operationQueue) ) - let referendumsOperationFactory = Gov2OperationFactory( - requestFactory: requestFactory, - operationQueue: OperationManagerFacade.sharedDefaultQueue - ) - let identityOperationFactory = IdentityOperationFactory( requestFactory: requestFactory, emptyIdentitiesWhenNoStorage: true diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index a2ba36dd91..89a3d32d62 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -11,7 +11,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani let chainRegistry: ChainRegistryProtocol let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol - let lockStateFactory: GovernanceLockStateFactoryProtocol let applicationHandler: ApplicationHandlerProtocol let serviceFactory: GovernanceServiceFactoryProtocol let operationQueue: OperationQueue @@ -37,7 +36,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani chainRegistry: ChainRegistryProtocol, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, - lockStateFactory: GovernanceLockStateFactoryProtocol, serviceFactory: GovernanceServiceFactoryProtocol, applicationHandler: ApplicationHandlerProtocol, operationQueue: OperationQueue, @@ -48,7 +46,6 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani self.chainRegistry = chainRegistry self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory - self.lockStateFactory = lockStateFactory self.serviceFactory = serviceFactory self.operationQueue = operationQueue self.applicationHandler = applicationHandler @@ -231,7 +228,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani return } - guard let referendumsOperationFactory = governanceState.operationFactory else { + guard let referendumsOperationFactory = governanceState.referendumsOperationFactory else { presenter?.didReceiveReferendums([]) return } @@ -357,6 +354,11 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { return } + guard let lockStateFactory = governanceState.locksOperationFactory else { + presenter?.didReceiveUnlockSchedule(.init(items: [])) + return + } + let wrapper = lockStateFactory.buildUnlockScheduleWrapper( for: tracksVoting, from: connection, diff --git a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift index 0b312386b0..64556c738c 100644 --- a/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift +++ b/novawallet/Modules/Vote/Parent/VoteChildPresenterFactory.swift @@ -102,11 +102,6 @@ final class VoteChildPresenterFactory { for state: GovernanceSharedState, wallet: MetaAccountModel ) -> ReferendumsInteractor { - let requestFactory = StorageRequestFactory( - remoteFactory: StorageKeyFactory(), - operationManager: OperationManager(operationQueue: operationQueue) - ) - let serviceFactory = GovernanceServiceFactory( chainRegisty: chainRegistry, storageFacade: substrateStorageFacade, @@ -115,18 +110,12 @@ final class VoteChildPresenterFactory { logger: logger ) - let lockStateFactory = Gov2LockStateFactory( - requestFactory: requestFactory, - unlocksCalculator: Gov2UnlocksCalculator() - ) - return ReferendumsInteractor( selectedMetaAccount: wallet, governanceState: state, chainRegistry: chainRegistry, walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, priceLocalSubscriptionFactory: priceProviderFactory, - lockStateFactory: lockStateFactory, serviceFactory: serviceFactory, applicationHandler: applicationHandler, operationQueue: operationQueue, From 9d9bdc41db0cef15f696dfeaf0ed376f1b441b05 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 7 Nov 2022 23:38:25 +0500 Subject: [PATCH 165/229] fix action fetch --- .../Substrate/Types/Support/SupportPallet.swift | 7 +++---- .../Action/Gov1ActionOperationFactory.swift | 14 ++++++++------ .../ReferendumDetailsViewFactory.swift | 10 +++------- .../ReferendumFullDetailsInteractor.swift | 1 - 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/novawallet/Common/Substrate/Types/Support/SupportPallet.swift b/novawallet/Common/Substrate/Types/Support/SupportPallet.swift index a4c266e44b..cf0c5ea8c0 100644 --- a/novawallet/Common/Substrate/Types/Support/SupportPallet.swift +++ b/novawallet/Common/Substrate/Types/Support/SupportPallet.swift @@ -48,11 +48,10 @@ enum SupportPallet { init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() - if let boundedCall = try? container.decode(Bounded.self) { - wrappedValue = boundedCall - } else { - let hash = try container.decode(BytesCodable.self).wrappedValue + if let hash = try? container.decode(BytesCodable.self).wrappedValue, hash.count == 32 { wrappedValue = .legacy(hash: hash) + } else { + wrappedValue = try container.decode(Bounded.self) } } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Action/Gov1ActionOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Action/Gov1ActionOperationFactory.swift index a76a3db5cb..f1bf561188 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Action/Gov1ActionOperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Action/Gov1ActionOperationFactory.swift @@ -18,16 +18,16 @@ final class Gov1ActionOperationFactory: GovernanceActionOperationFactory { private func createDemocracyPreimageWrapper( dependingOn keyEncodingOperation: BaseOperation<[Data]>, - storageSizeOperation: BaseOperation, + storageSizeOperation: BaseOperation, connection: JSONRPCEngine, codingFactory: RuntimeCoderFactoryProtocol ) -> BaseOperation<[ReferendumActionLocal.Call>?]> { OperationCombiningService>?>( operationManager: OperationManager(operationQueue: operationQueue) ) { - let result = try storageSizeOperation.extractNoCancellableResultData() + let optResult = try storageSizeOperation.extractNoCancellableResultData() - if let size = BigUInt.fromHexString(result), size <= Self.maxFetchCallSize { + if let size = optResult, size <= Self.maxFetchCallSize { let callFetchWrapper: CompoundOperationWrapper<[StorageResponse]> = self.requestFactory.queryItems( engine: connection, @@ -86,7 +86,10 @@ final class Gov1ActionOperationFactory: GovernanceActionOperationFactory { keyEncodingOperation.codingFactory = codingFactory keyEncodingOperation.keyParams = [BytesCodable(wrappedValue: hash)] - let storageSizeOperation = JSONRPCListOperation(engine: connection, method: RemoteStorageSize.method) + let storageSizeOperation = JSONRPCListOperation( + engine: connection, + method: RemoteStorageSize.method + ) storageSizeOperation.configurationBlock = { do { @@ -136,8 +139,7 @@ final class Gov1ActionOperationFactory: GovernanceActionOperationFactory { ) { let codingFactory = try codingFactoryOperation.extractNoCancellableResultData() - let callPath = Democracy.preimages - if codingFactory.metadata.getCall(from: callPath.moduleName, with: callPath.itemName) != nil { + if codingFactory.metadata.getStorageMetadata(for: Democracy.preimages) != nil { let wrapper = self.fetchDemocracyPreimage( for: hash, connection: connection, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index eb6fbe9251..abcf97b109 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -98,7 +98,8 @@ struct ReferendumDetailsViewFactory { let connection = chainRegistry.getConnection(for: chain.chainId), let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId), let blockTimeService = state.blockTimeService, - let subscriptionFactory = state.subscriptionFactory else { + let subscriptionFactory = state.subscriptionFactory, + let actionDetailsFactory = state.createActionsDetailsFactory(for: chain) else { return nil } @@ -108,11 +109,6 @@ struct ReferendumDetailsViewFactory { operationManager: OperationManager(operationQueue: operationQueue) ) - let actionDetailsOperationFactory = Gov2ActionOperationFactory( - requestFactory: requestFactory, - operationQueue: operationQueue - ) - let identityOperationFactory = IdentityOperationFactory( requestFactory: requestFactory, emptyIdentitiesWhenNoStorage: true @@ -124,7 +120,7 @@ struct ReferendumDetailsViewFactory { referendum: referendum, selectedAccount: selectedAccount, chain: chain, - actionDetailsOperationFactory: actionDetailsOperationFactory, + actionDetailsOperationFactory: actionDetailsFactory, connection: connection, runtimeProvider: runtimeProvider, blockTimeService: blockTimeService, diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift index 6beeb459c5..3113c62394 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsInteractor.swift @@ -5,7 +5,6 @@ final class ReferendumFullDetailsInteractor { weak var presenter: ReferendumFullDetailsInteractorOutputProtocol? let chain: ChainModel let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol - let currencyManager: CurrencyManagerProtocol let operationQueue: OperationQueue let processingOperationFactory: PrettyPrintedJSONOperationFactoryProtocol let referendumAction: ReferendumActionLocal From 90e7c0a37eedf6e19cbd5ba6bb49b0ae3fa5f4c1 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 7 Nov 2022 23:58:14 +0500 Subject: [PATCH 166/229] fix tests --- .../Migration/SubstrateStorageMigrationTests.swift | 8 ++++---- .../Governance/GovernanceUnlocksTestBuilding.swift | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift b/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift index ce602d3d09..09aa881f6c 100644 --- a/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift +++ b/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift @@ -31,14 +31,14 @@ final class SubstrateStorageMigrationTests: XCTestCase { try removeDirectory(at: databaseDirectoryURL) } - func testMigrationVersion2ToVersion3() { + func testMigrationVersion3ToVersion4() { let timeout: TimeInterval = 5 let generatedChains = generateChainsWithTimeout(timeout) XCTAssertGreaterThan(generatedChains.count, 0) let migrator = SubstrateStorageMigrator(storeURL: storeURL, modelDirectory: modelDirectory, - model: .version3, + model: .version4, fileManager: FileManager.default) XCTAssertTrue(migrator.requiresMigration(), "Migration is not required") @@ -95,7 +95,7 @@ final class SubstrateStorageMigrationTests: XCTestCase { private func generateChains(completion: @escaping (Result<[ChainModel], Error>) -> Void) { let chains = ChainModelGenerator.generate(count: 5) - let dbService = createCoreDataService(for: .version2) + let dbService = createCoreDataService(for: .version3) dbService.performAsync { [unowned self] (context, error) in if let error = error { @@ -132,7 +132,7 @@ final class SubstrateStorageMigrationTests: XCTestCase { } private func fetchChains(completion: @escaping (Result<[ChainModel], Error>) -> Void) { - let dbService = createCoreDataService(for: .version3) + let dbService = createCoreDataService(for: .version4) dbService.performAsync { [unowned self] (context, error) in if let error = error { diff --git a/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift b/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift index dba3d41763..e82fb4bad1 100644 --- a/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift +++ b/novawalletTests/Modules/Governance/GovernanceUnlocksTestBuilding.swift @@ -55,25 +55,27 @@ enum GovernanceUnlocksTestBuilding { let tracksVoting = compoundVoting.votingDistribution let refendumsUnlock = compoundVoting.referendumsUnlock - let initReferendums = [ReferendumIdLocal: ReferendumInfo]() + let initReferendums = [ReferendumIdLocal: GovUnlockReferendumProtocol]() let referendums = tracksVoting.votes.tracksByReferendums().keys.reduce(into: initReferendums) { (accum, referendumId) in let deposit = Referenda.Deposit(who: AccountId.zeroAccountId(of: 32), amount: BigUInt(0)) - accum[referendumId] = ReferendumInfo.approved( + let referendum = ReferendumInfo.approved( .init( since: refendumsUnlock[referendumId] ?? 0, submissionDeposit: deposit, decisionDeposit: deposit ) ) + + accum[referendumId] = Gov2UnlockReferendum(referendumInfo: referendum) } let additions = GovUnlockCalculationInfo( - tracks: [:], + decisionPeriods: [:], undecidingTimeout: 0, voteLockingPeriod: 0 ) - let schedule = Gov2UnlocksCalculator().createUnlocksSchedule( + let schedule = GovUnlocksCalculator().createUnlocksSchedule( for: tracksVoting, referendums: referendums, additionalInfo: additions From 17849700a636d9f87e0c82745929c3369eb48bb6 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 8 Nov 2022 10:00:30 +0500 Subject: [PATCH 167/229] fix locks --- .../Operation/Gov1LocalMappingFactory.swift | 67 ++++++++++--------- .../Gov1OperationFactory+Protocol.swift | 31 +++++++-- .../Gov1SubscriptionFactory.swift | 9 ++- 3 files changed, 70 insertions(+), 37 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift index 76b5d36470..daedf9ecc5 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift @@ -1,4 +1,5 @@ import Foundation +import BigInt final class Gov1LocalMappingFactory { private func mapOngoing( @@ -59,8 +60,41 @@ final class Gov1LocalMappingFactory { return .init(index: ReferendumIdLocal(index), state: .rejected(model: rejected), proposer: nil) } } +} + +extension Gov1LocalMappingFactory { + func mapRemote( + referendum: Democracy.ReferendumInfo, + index: Referenda.ReferendumIndex, + additionalInfo: Gov1OperationFactory.AdditionalInfo + ) -> ReferendumLocal? { + switch referendum { + case let .ongoing(status): + return mapOngoing(referendum: status, index: index, additionalInfo: additionalInfo) + case let .finished(status): + return mapFinished(referendum: status, index: index, additionalInfo: additionalInfo) + case .unknown: + return nil + } + } + + func mapToTracksVoting( + _ voting: Democracy.Voting?, + lockedBalance: BigUInt?, maxVotes: UInt32 + ) -> ReferendumTracksVotingDistribution { + let accountVoting = mapToAccountVoting(voting, maxVotes: maxVotes) + + let trackId = Gov1OperationFactory.trackId + + if let lockedBalance = lockedBalance, lockedBalance > 0 { + let trackLock = ConvictionVoting.ClassLock(trackId: trackId, amount: lockedBalance) + return .init(votes: accountVoting, trackLocks: [trackLock]) + } else { + return .init(votes: accountVoting, trackLocks: []) + } + } - private func mapToAccountVoting( + func mapToAccountVoting( _ voting: Democracy.Voting?, maxVotes: UInt32 ) -> ReferendumAccountVotingDistribution { @@ -90,34 +124,3 @@ final class Gov1LocalMappingFactory { } } } - -extension Gov1LocalMappingFactory { - func mapRemote( - referendum: Democracy.ReferendumInfo, - index: Referenda.ReferendumIndex, - additionalInfo: Gov1OperationFactory.AdditionalInfo - ) -> ReferendumLocal? { - switch referendum { - case let .ongoing(status): - return mapOngoing(referendum: status, index: index, additionalInfo: additionalInfo) - case let .finished(status): - return mapFinished(referendum: status, index: index, additionalInfo: additionalInfo) - case .unknown: - return nil - } - } - - func mapVoting(_ voting: Democracy.Voting?, maxVotes: UInt32) -> ReferendumTracksVotingDistribution { - let accountVoting = mapToAccountVoting(voting, maxVotes: maxVotes) - - let trackId = Gov1OperationFactory.trackId - let lockedBalance = accountVoting.lockedBalance(for: TrackIdLocal(trackId)) - - if lockedBalance > 0 { - let trackLock = ConvictionVoting.ClassLock(trackId: trackId, amount: lockedBalance) - return .init(votes: accountVoting, trackLocks: [trackLock]) - } else { - return .init(votes: accountVoting, trackLocks: []) - } - } -} diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift index 42d0fc1c61..6b75aed0e4 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift @@ -92,22 +92,45 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { func fetchTracksVotingWrapper( for voting: Democracy.Voting?, - runtimeProvider: RuntimeProviderProtocol + accountId: AccountId, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? ) -> CompoundOperationWrapper { let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + let lockKeys: () throws -> [BytesCodable] = { + [BytesCodable(wrappedValue: accountId)] + } + + let locksWrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( + engine: connection, + keyParams: lockKeys, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: .balanceLocks, + at: blockHash + ) + + locksWrapper.addDependency(operations: [codingFactoryOperation]) + let maxVotesOperation = createMaxVotesOperation(dependingOn: codingFactoryOperation) maxVotesOperation.addDependency(codingFactoryOperation) let mappingOperation = ClosureOperation { let maxVotes = try maxVotesOperation.extractNoCancellableResultData() + let locks = try locksWrapper.targetOperation.extractNoCancellableResultData().first?.value + + let lockedAmount = locks? + .first { String(data: $0.identifier, encoding: .utf8) == Democracy.lockId }? + .amount ?? 0 - return Gov1LocalMappingFactory().mapVoting(voting, maxVotes: maxVotes) + return Gov1LocalMappingFactory().mapToTracksVoting(voting, lockedBalance: lockedAmount, maxVotes: maxVotes) } mappingOperation.addDependency(maxVotesOperation) + mappingOperation.addDependency(locksWrapper.targetOperation) - let dependencies = [codingFactoryOperation, maxVotesOperation] + let dependencies = [codingFactoryOperation, maxVotesOperation] + locksWrapper.allOperations return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: dependencies) } @@ -142,7 +165,7 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { let optVoting = try votesWrapper.targetOperation.extractNoCancellableResultData().first?.value let maxVotes = try maxVotesOperation.extractNoCancellableResultData() - return Gov1LocalMappingFactory().mapVoting(optVoting, maxVotes: maxVotes).votes + return Gov1LocalMappingFactory().mapToAccountVoting(optVoting, maxVotes: maxVotes) } mappingOperation.addDependency(votesWrapper.targetOperation) diff --git a/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift b/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift index 4f7923585a..bb9c7062ae 100644 --- a/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift +++ b/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift @@ -108,6 +108,7 @@ final class Gov1SubscriptionFactory: AnyCancellableCleaning { private func handleVotesResult( _ result: Result, Error>, + connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, accountId: AccountId ) { @@ -119,6 +120,7 @@ final class Gov1SubscriptionFactory: AnyCancellableCleaning { case let .success(result): handleVotes( for: result.value, + connection: connection, runtimeProvider: runtimeProvider, accountId: accountId, blockHash: result.blockHash @@ -130,6 +132,7 @@ final class Gov1SubscriptionFactory: AnyCancellableCleaning { private func handleVotes( for votes: Democracy.Voting?, + connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, accountId: AccountId, blockHash: Data? @@ -139,7 +142,10 @@ final class Gov1SubscriptionFactory: AnyCancellableCleaning { let wrapper = operationFactory.fetchTracksVotingWrapper( for: votes, - runtimeProvider: runtimeProvider + accountId: accountId, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash ) wrapper.targetOperation.completionBlock = { [weak self] in @@ -268,6 +274,7 @@ extension Gov1SubscriptionFactory: GovernanceSubscriptionFactoryProtocol { ) { [weak self] result in self?.handleVotesResult( result, + connection: connection, runtimeProvider: runtimeProvider, accountId: accountId ) From 3a73b5ff94fd470d588d8e0836019606a8fd8d06 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 8 Nov 2022 11:51:50 +0500 Subject: [PATCH 168/229] fix thresholds --- .../DemocracyDecidingFunctionProtocol.swift | 44 ++++--------------- 1 file changed, 8 insertions(+), 36 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift b/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift index c4ab4bfc2e..9974f19480 100644 --- a/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift +++ b/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift @@ -18,50 +18,32 @@ final class Gov1DecidingFunction { self.thresholdType = thresholdType } - private func calculateSupermajorityApprove( - for ayes: BigUInt, - nays: BigUInt, - turnout: BigUInt, - electorate: BigUInt - ) -> Decimal? { + private func calculateSupermajorityApprove(turnout: BigUInt, electorate: BigUInt) -> Decimal? { guard - let totalDecimal = Decimal(ayes + nays), - let naysDecimal = Decimal(nays), let turnoutSqrt = Decimal(turnout.squareRoot()), let electorateSqrt = Decimal(electorate.squareRoot()) else { return nil } - guard totalDecimal > 0, turnoutSqrt > 0 else { + guard electorateSqrt + turnoutSqrt > 0 else { return nil } - let naysFraction = naysDecimal / totalDecimal - - return naysFraction * (electorateSqrt / turnoutSqrt) + return electorateSqrt / (electorateSqrt + turnoutSqrt) } - private func calculateSupermajorityAgainst( - for ayes: BigUInt, - nays: BigUInt, - turnout: BigUInt, - electorate: BigUInt - ) -> Decimal? { + private func calculateSupermajorityAgainst(turnout: BigUInt, electorate: BigUInt) -> Decimal? { guard - let totalDecimal = Decimal(ayes + nays), - let naysDecimal = Decimal(nays), let turnoutSqrt = Decimal(turnout.squareRoot()), let electorateSqrt = Decimal(electorate.squareRoot()) else { return nil } - guard totalDecimal > 0, electorateSqrt > 0 else { + guard electorateSqrt + turnoutSqrt > 0 else { return nil } - let naysFraction = naysDecimal / totalDecimal - - return naysFraction * (turnoutSqrt / electorateSqrt) + return turnoutSqrt / (electorateSqrt + turnoutSqrt) } } @@ -74,19 +56,9 @@ extension Gov1DecidingFunction: DemocracyDecidingFunctionProtocol { ) -> Decimal? { switch thresholdType { case .superMajorityApprove: - return calculateSupermajorityApprove( - for: ayes, - nays: nays, - turnout: turnout, - electorate: electorate - ) + return calculateSupermajorityApprove(turnout: turnout, electorate: electorate) case .superMajorityAgainst: - return calculateSupermajorityAgainst( - for: ayes, - nays: nays, - turnout: turnout, - electorate: electorate - ) + return calculateSupermajorityAgainst(turnout: turnout, electorate: electorate) case .simpleMajority: return 0.5 case .unknown: From 242d24cf1e0fa88390f79f6c143571de1ab9d937 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Tue, 8 Nov 2022 13:27:27 +0500 Subject: [PATCH 169/229] Update novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift Co-authored-by: Gulnaz <666lynx666@mail.ru> --- .../Vote/Governance/Operation/Gov1LocalMappingFactory.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift index daedf9ecc5..107b1b226b 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift @@ -80,7 +80,8 @@ extension Gov1LocalMappingFactory { func mapToTracksVoting( _ voting: Democracy.Voting?, - lockedBalance: BigUInt?, maxVotes: UInt32 + lockedBalance: BigUInt?, + maxVotes: UInt32 ) -> ReferendumTracksVotingDistribution { let accountVoting = mapToAccountVoting(voting, maxVotes: maxVotes) From 4dc46ad6114ffcfbfb01b4717ac477445194488e Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 9 Nov 2022 01:59:45 +0500 Subject: [PATCH 170/229] add polkassembly datasource --- novawallet.xcodeproj/project.pbxproj | 36 +++- .../GovMetadataLocalSubscriptionFactory.swift | 148 +++++++++++++-- .../Gov2MetadataProviderSource.swift | 10 - ...erendumMetadataDetailsProviderSource.swift | 97 ++++++++++ ...rendumsMetadataPreviewProviderSource.swift | 97 ++++++++++ .../GovMetadataLocalStorageSubscriber.swift | 33 +++- .../Foundation/NSPredicate+Filter.swift | 8 + .../Migration/SubstrateStorageVersion.swift | 3 + .../Model/ChainRegistry/ChainModel.swift | 5 +- .../PolkassemblyOperationFactory.swift | 164 ++++++++++++++++ .../EntityToModel/ChainModelMapper.swift | 76 +++++--- .../ReferendumMetadataMapper.swift | 54 ++++++ .../.xccurrentversion | 2 +- .../SubstrateDataModel5.xcdatamodel/contents | 178 ++++++++++++++++++ .../DemocracyDecidingFunctionProtocol.swift | 4 +- .../Model/GovernanceOffchainApi.swift | 5 + .../Model/GovernanceSharedState.swift | 16 +- .../Model/ReferendumMetadataLocal.swift | 38 +++- 18 files changed, 893 insertions(+), 81 deletions(-) delete mode 100644 novawallet/Common/DataProvider/Sources/Governance/Gov2MetadataProviderSource.swift create mode 100644 novawallet/Common/DataProvider/Sources/Governance/ReferendumMetadataDetailsProviderSource.swift create mode 100644 novawallet/Common/DataProvider/Sources/Governance/ReferendumsMetadataPreviewProviderSource.swift create mode 100644 novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift create mode 100644 novawallet/Common/Storage/EntityToModel/ReferendumMetadataMapper.swift create mode 100644 novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel5.xcdatamodel/contents create mode 100644 novawallet/Modules/Vote/Governance/Model/GovernanceOffchainApi.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 34d7f32f96..28785162d2 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -426,7 +426,7 @@ 8411707C285B1214006F4DFB /* XcmTransfers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411707B285B1214006F4DFB /* XcmTransfers.swift */; }; 8411707F285B15E0006F4DFB /* XcmTransfersSyncService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411707E285B15E0006F4DFB /* XcmTransfersSyncService.swift */; }; 8412219B28F04EA600715C82 /* GovMetadataLocalSubscriptionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219A28F04EA600715C82 /* GovMetadataLocalSubscriptionFactory.swift */; }; - 8412219E28F0514400715C82 /* Gov2MetadataProviderSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219D28F0514400715C82 /* Gov2MetadataProviderSource.swift */; }; + 8412219E28F0514400715C82 /* ReferendumsMetadataPreviewProviderSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219D28F0514400715C82 /* ReferendumsMetadataPreviewProviderSource.swift */; }; 841221A028F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8412219F28F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift */; }; 841221A228F0520300715C82 /* GovMetadataLocalStorageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841221A128F0520300715C82 /* GovMetadataLocalStorageHandler.swift */; }; 841221A428F0A3F200715C82 /* ReferendumAccountVoteLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */; }; @@ -1497,6 +1497,7 @@ 8493D0E326FF571D00A28008 /* PriceProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8493D0E226FF571D00A28008 /* PriceProviderFactory.swift */; }; 8493D3E62705994200157009 /* StakingSharedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8493D3E52705994200157009 /* StakingSharedState.swift */; }; 8493D3E927059B6700157009 /* StakingServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8493D3E827059B6700157009 /* StakingServiceFactory.swift */; }; + 8493FF38291A59D800F09F1B /* ReferendumMetadataMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8493FF37291A59D800F09F1B /* ReferendumMetadataMapper.swift */; }; 8494424A265306BD0016E7BD /* ChangeRewardDestinationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84944249265306BD0016E7BD /* ChangeRewardDestinationViewModel.swift */; }; 84948C36287DD1C800E6DD3E /* NftListRMRKV2ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84948C35287DD1C800E6DD3E /* NftListRMRKV2ViewModel.swift */; }; 84948C38287E0B4F00E6DD3E /* FilterImageProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84948C37287E0B4F00E6DD3E /* FilterImageProcessor.swift */; }; @@ -1861,6 +1862,9 @@ 84C7DA5425EE2DF000F8C318 /* StakingErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C7DA5325EE2DF000F8C318 /* StakingErrorPresentable.swift */; }; 84C91FAA261E724F002796B9 /* SwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C91FA9261E724F002796B9 /* SwitchTableViewCell.swift */; }; 84C91FAF261E7CDD002796B9 /* WalletHistoryFilterEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C91FAE261E7CDD002796B9 /* WalletHistoryFilterEditor.swift */; }; + 84C9CF3B291AE328002BF328 /* PolkassemblyOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9CF3A291AE328002BF328 /* PolkassemblyOperationFactory.swift */; }; + 84C9CF3D291AF1B1002BF328 /* GovernanceOffchainApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9CF3C291AF1B1002BF328 /* GovernanceOffchainApi.swift */; }; + 84C9CF3F291AF4B2002BF328 /* ReferendumMetadataDetailsProviderSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9CF3E291AF4B2002BF328 /* ReferendumMetadataDetailsProviderSource.swift */; }; 84CA68CF26BD6872003B9453 /* RuntimeSyncService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CA68CE26BD6872003B9453 /* RuntimeSyncService.swift */; }; 84CA68D126BE99ED003B9453 /* RuntimeProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CA68D026BE99ED003B9453 /* RuntimeProviderFactory.swift */; }; 84CA68D326BE9A35003B9453 /* RuntimeProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CA68D226BE9A35003B9453 /* RuntimeProvider.swift */; }; @@ -3394,7 +3398,7 @@ 8411707B285B1214006F4DFB /* XcmTransfers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcmTransfers.swift; sourceTree = ""; }; 8411707E285B15E0006F4DFB /* XcmTransfersSyncService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcmTransfersSyncService.swift; sourceTree = ""; }; 8412219A28F04EA600715C82 /* GovMetadataLocalSubscriptionFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalSubscriptionFactory.swift; sourceTree = ""; }; - 8412219D28F0514400715C82 /* Gov2MetadataProviderSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gov2MetadataProviderSource.swift; sourceTree = ""; }; + 8412219D28F0514400715C82 /* ReferendumsMetadataPreviewProviderSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsMetadataPreviewProviderSource.swift; sourceTree = ""; }; 8412219F28F051EE00715C82 /* GovMetadataLocalStorageSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalStorageSubscriber.swift; sourceTree = ""; }; 841221A128F0520300715C82 /* GovMetadataLocalStorageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovMetadataLocalStorageHandler.swift; sourceTree = ""; }; 841221A328F0A3F200715C82 /* ReferendumAccountVoteLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumAccountVoteLocal.swift; sourceTree = ""; }; @@ -4479,6 +4483,8 @@ 8493D0E226FF571D00A28008 /* PriceProviderFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceProviderFactory.swift; sourceTree = ""; }; 8493D3E52705994200157009 /* StakingSharedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingSharedState.swift; sourceTree = ""; }; 8493D3E827059B6700157009 /* StakingServiceFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingServiceFactory.swift; sourceTree = ""; }; + 8493FF36291A3D4C00F09F1B /* SubstrateDataModel5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SubstrateDataModel5.xcdatamodel; sourceTree = ""; }; + 8493FF37291A59D800F09F1B /* ReferendumMetadataMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumMetadataMapper.swift; sourceTree = ""; }; 84944249265306BD0016E7BD /* ChangeRewardDestinationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeRewardDestinationViewModel.swift; sourceTree = ""; }; 84948C35287DD1C800E6DD3E /* NftListRMRKV2ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NftListRMRKV2ViewModel.swift; sourceTree = ""; }; 84948C37287E0B4F00E6DD3E /* FilterImageProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterImageProcessor.swift; sourceTree = ""; }; @@ -4844,6 +4850,9 @@ 84C7DA5325EE2DF000F8C318 /* StakingErrorPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingErrorPresentable.swift; sourceTree = ""; }; 84C91FA9261E724F002796B9 /* SwitchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchTableViewCell.swift; sourceTree = ""; }; 84C91FAE261E7CDD002796B9 /* WalletHistoryFilterEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletHistoryFilterEditor.swift; sourceTree = ""; }; + 84C9CF3A291AE328002BF328 /* PolkassemblyOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkassemblyOperationFactory.swift; sourceTree = ""; }; + 84C9CF3C291AF1B1002BF328 /* GovernanceOffchainApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceOffchainApi.swift; sourceTree = ""; }; + 84C9CF3E291AF4B2002BF328 /* ReferendumMetadataDetailsProviderSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumMetadataDetailsProviderSource.swift; sourceTree = ""; }; 84CA68CE26BD6872003B9453 /* RuntimeSyncService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeSyncService.swift; sourceTree = ""; }; 84CA68D026BE99ED003B9453 /* RuntimeProviderFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeProviderFactory.swift; sourceTree = ""; }; 84CA68D226BE9A35003B9453 /* RuntimeProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeProvider.swift; sourceTree = ""; }; @@ -6898,7 +6907,8 @@ 8412219C28F0512B00715C82 /* Governance */ = { isa = PBXGroup; children = ( - 8412219D28F0514400715C82 /* Gov2MetadataProviderSource.swift */, + 8412219D28F0514400715C82 /* ReferendumsMetadataPreviewProviderSource.swift */, + 84C9CF3E291AF4B2002BF328 /* ReferendumMetadataDetailsProviderSource.swift */, ); path = Governance; sourceTree = ""; @@ -8119,6 +8129,7 @@ 8499FECB27BF8F4A00712589 /* NftModelMapper.swift */, 84F3B27727F4179A00D64CF5 /* PhishingSiteMapper.swift */, 849E07F5284A114B00DE0440 /* ParaStkScheduledRequestsMapper.swift */, + 8493FF37291A59D800F09F1B /* ReferendumMetadataMapper.swift */, ); path = EntityToModel; sourceTree = ""; @@ -9974,6 +9985,7 @@ 8490150124AB6BEA008F705E /* Network */ = { isa = PBXGroup; children = ( + 84C9CF39291AE30F002BF328 /* Polkassembly */, 843E9B3027C8B1D4009C143A /* Files */, 8499FE6D27BE1ABF00712589 /* BaseOperationFactory */, 8499FE6427BD15AC00712589 /* DistributedStorage */, @@ -11462,6 +11474,14 @@ path = Protocols; sourceTree = ""; }; + 84C9CF39291AE30F002BF328 /* Polkassembly */ = { + isa = PBXGroup; + children = ( + 84C9CF3A291AE328002BF328 /* PolkassemblyOperationFactory.swift */, + ); + path = Polkassembly; + sourceTree = ""; + }; 84CAF52524BEEF2F00F4C295 /* JSONRPC */ = { isa = PBXGroup; children = ( @@ -11724,6 +11744,7 @@ 843461E7290BF14400379936 /* ReferendumsSorting.swift */, 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */, 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */, + 84C9CF3C291AF1B1002BF328 /* GovernanceOffchainApi.swift */, ); path = Model; sourceTree = ""; @@ -15063,6 +15084,7 @@ AEE5FAFF26415E0C002B8FDC /* StakingRebondSetupPresenter.swift in Sources */, 84A3B8A02836D74B00DE2669 /* StorageKeyDecodingProtocol.swift in Sources */, 84FB9E1C285C57EF00B42FC0 /* XcmMultilocation.swift in Sources */, + 84C9CF3F291AF4B2002BF328 /* ReferendumMetadataDetailsProviderSource.swift in Sources */, 8407715E28CBE28D007DBD24 /* ParaStkYieldBoostSetupPresenter+Cancel.swift in Sources */, 8472975D260B1B71009B86D0 /* ExistingBonding.swift in Sources */, 8490144C24A93D0B008F705E /* FearlessNavigationController.swift in Sources */, @@ -15913,7 +15935,7 @@ 84C2064028D1EAD2006D0D52 /* AccountAssetBalanceTrigger.swift in Sources */, 8469D5A628F5E8F20074FEE3 /* Staking.swift in Sources */, 848FFE8325E686C200652AA5 /* StorageDecodingOperation.swift in Sources */, - 8412219E28F0514400715C82 /* Gov2MetadataProviderSource.swift in Sources */, + 8412219E28F0514400715C82 /* ReferendumsMetadataPreviewProviderSource.swift in Sources */, 8488ECDF258CE118004591CC /* PurchaseCompleted.swift in Sources */, 84AE7AA727D36E4D00495267 /* IconDetailsGenericView.swift in Sources */, 840BF22726C2C8A600E3A955 /* ChainSyncEvents.swift in Sources */, @@ -16694,6 +16716,7 @@ EB5F587A71CCE1F0F86154CF /* ControllerAccountViewFactory.swift in Sources */, 9A940CBA3F309D438945A90C /* ControllerAccountConfirmationProtocols.swift in Sources */, AE1000F226679886004753B7 /* ChangeTargetsRecommendationWireframe.swift in Sources */, + 84C9CF3B291AE328002BF328 /* PolkassemblyOperationFactory.swift in Sources */, D886425A55425810AD070AB5 /* ControllerAccountConfirmationWireframe.swift in Sources */, 84D17EDE28054CC400F7BAFF /* DAppLocalSubscriptionFactory.swift in Sources */, 84E2589F2892B5AF00DC8A51 /* WalletSwitchPresentable.swift in Sources */, @@ -17314,6 +17337,7 @@ 441FFD82C502D7300B79EE66 /* ReferendumVoteConfirmProtocols.swift in Sources */, F35B520D7955A70588AB593C /* ReferendumVoteConfirmWireframe.swift in Sources */, F0ADB63765A8EAA19D85C30B /* ReferendumVoteConfirmPresenter.swift in Sources */, + 84C9CF3D291AF1B1002BF328 /* GovernanceOffchainApi.swift in Sources */, DE52F23521D54A07F558EB1B /* ReferendumVoteConfirmInteractor.swift in Sources */, B30FEC6F62918BC6F38396A2 /* ReferendumVoteConfirmViewController.swift in Sources */, 163709FEE6203813261DD771 /* ReferendumVoteConfirmViewLayout.swift in Sources */, @@ -17323,6 +17347,7 @@ 9097EE6D11E2E023D2637BE5 /* GovernanceUnlockSetupPresenter.swift in Sources */, 38D0977931828C7894579968 /* GovernanceUnlockSetupInteractor.swift in Sources */, 16098DABB1C9C058C1965F1D /* GovernanceUnlockSetupViewController.swift in Sources */, + 8493FF38291A59D800F09F1B /* ReferendumMetadataMapper.swift in Sources */, 0E71EA5AE04940824AEA01C7 /* GovernanceUnlockSetupViewLayout.swift in Sources */, E28F3762EAC9A4E5D21342D4 /* GovernanceUnlockSetupViewFactory.swift in Sources */, 9DE1757D047A4D1E97913774 /* GovernanceUnlockConfirmProtocols.swift in Sources */, @@ -18137,12 +18162,13 @@ 843910CA253F7E6500E3C217 /* SubstrateDataModel.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 8493FF36291A3D4C00F09F1B /* SubstrateDataModel5.xcdatamodel */, 845B08112918E343005785D3 /* SubstrateDataModel4.xcdatamodel */, 84D8754628EB726E004065BD /* SubstrateDataModel3.xcdatamodel */, 88787F0328DB3A7B00B115AB /* SubstrateDataModel2.xcdatamodel */, 843910CB253F7E6500E3C217 /* SubstrateDataModel.xcdatamodel */, ); - currentVersion = 845B08112918E343005785D3 /* SubstrateDataModel4.xcdatamodel */; + currentVersion = 8493FF36291A3D4C00F09F1B /* SubstrateDataModel5.xcdatamodel */; path = SubstrateDataModel.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift index 1c21429ac0..9c3385a512 100644 --- a/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift +++ b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift @@ -6,44 +6,162 @@ typealias ReferendumMetadataMapping = [ReferendumIdLocal: ReferendumMetadataLoca protocol GovMetadataLocalSubscriptionFactoryProtocol: AnyObject { func getMetadataProvider( for chain: ChainModel - ) -> AnySingleValueProvider + ) -> StreamableProvider? + + func getMetadataProvider( + for chain: ChainModel, + referendumId: ReferendumIdLocal + ) -> StreamableProvider? } final class GovMetadataLocalSubscriptionFactory { private var providers: [String: WeakWrapper] = [:] let storageFacade: StorageFacadeProtocol + let operationQueue: OperationQueue + let logger: LoggerProtocol - init(storageFacade: StorageFacadeProtocol) { + init(storageFacade: StorageFacadeProtocol, operationQueue: OperationQueue, logger: LoggerProtocol) { self.storageFacade = storageFacade + self.operationQueue = operationQueue + self.logger = logger } } extension GovMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { func getMetadataProvider( for chain: ChainModel - ) -> AnySingleValueProvider { - let identifier = "gov-metadata" + chain.chainId + ) -> StreamableProvider? { + guard + let governanceApi = chain.externalApi?.governance, + let apiType = GovernanceOffchainApi(rawValue: governanceApi.type) else { + return nil + } + + let chainId = chain.chainId + let url = governanceApi.url + + let identifier = "gov-metadata-preview" + chainId + + if let provider = providers[identifier]?.target as? StreamableProvider { + return provider + } + + let mapper = ReferendumMetadataMapper() + let repository = storageFacade.createRepository( + filter: NSPredicate.referendums(for: chainId), + sortDescriptors: [], + mapper: AnyCoreDataMapper(mapper)) + + let operationFactory: PolkassemblyOperationFactoryProtocol + + switch apiType { + case .polkassembly: + operationFactory = PolkassemblyChainOperationFactory( + chainId: chainId, + url: url + ) + } + + let source = ReferendumsMetadataPreviewProviderSource( + operationFactory: operationFactory, + repository: AnyDataProviderRepository(repository), + operationQueue: operationQueue + ) + + let observable = CoreDataContextObservable( + service: storageFacade.databaseService, + mapper: AnyCoreDataMapper(mapper), + predicate: { entity in + chainId == entity.chainId + } + ) - if let provider = providers[identifier]?.target as? SingleValueProvider { - return AnySingleValueProvider(provider) + observable.start { [weak self] error in + if let error = error { + self?.logger.error("Did receive error: \(error)") + } } - let repository: CoreDataRepository = - storageFacade.createRepository() + let provider = StreamableProvider( + source: AnyStreamableSource(source), + repository: AnyDataProviderRepository(repository), + observable: AnyDataProviderRepositoryObservable(observable), + operationManager: OperationManager(operationQueue: operationQueue) + ) + + providers[identifier] = WeakWrapper(target: provider) - let source = Gov2MetadataProviderSource() + return provider + } + + func getMetadataProvider( + for chain: ChainModel, + referendumId: ReferendumIdLocal + ) -> StreamableProvider? { + guard + let governanceApi = chain.externalApi?.governance, + let apiType = GovernanceOffchainApi(rawValue: governanceApi.type) else { + return nil + } + + let chainId = chain.chainId + let url = governanceApi.url + + let identifier = "gov-metadata-details" + chainId + String(referendumId) + + if let provider = providers[identifier]?.target as? StreamableProvider { + return provider + } + + let mapper = ReferendumMetadataMapper() + let repository = storageFacade.createRepository( + filter: NSPredicate.referendums(for: chainId), + sortDescriptors: [], + mapper: AnyCoreDataMapper(mapper)) + + let operationFactory: PolkassemblyOperationFactoryProtocol + + switch apiType { + case .polkassembly: + operationFactory = PolkassemblyChainOperationFactory( + chainId: chainId, + url: url + ) + } + + let source = ReferendumMetadataDetailsProviderSource( + chainId: chainId, + referendumId: referendumId, + operationFactory: operationFactory, + repository: AnyDataProviderRepository(repository), + operationQueue: operationQueue + ) + + let observable = CoreDataContextObservable( + service: storageFacade.databaseService, + mapper: AnyCoreDataMapper(mapper), + predicate: { entity in + chainId == entity.chainId && + referendumId == entity.referendumId + } + ) + + observable.start { [weak self] error in + if let error = error { + self?.logger.error("Did receive error: \(error)") + } + } - let trigger: DataProviderEventTrigger = [.onAddObserver, .onInitialization] - let provider = SingleValueProvider( - targetIdentifier: identifier, - source: AnySingleValueProviderSource(source), + let provider = StreamableProvider( + source: AnyStreamableSource(source), repository: AnyDataProviderRepository(repository), - updateTrigger: trigger + observable: AnyDataProviderRepositoryObservable(observable), + operationManager: OperationManager(operationQueue: operationQueue) ) providers[identifier] = WeakWrapper(target: provider) - return AnySingleValueProvider(provider) + return provider } } diff --git a/novawallet/Common/DataProvider/Sources/Governance/Gov2MetadataProviderSource.swift b/novawallet/Common/DataProvider/Sources/Governance/Gov2MetadataProviderSource.swift deleted file mode 100644 index aa48bdc314..0000000000 --- a/novawallet/Common/DataProvider/Sources/Governance/Gov2MetadataProviderSource.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation -import RobinHood - -final class Gov2MetadataProviderSource: SingleValueProviderSourceProtocol { - typealias Model = ReferendumMetadataMapping - - func fetchOperation() -> CompoundOperationWrapper { - CompoundOperationWrapper.createWithResult([:]) - } -} diff --git a/novawallet/Common/DataProvider/Sources/Governance/ReferendumMetadataDetailsProviderSource.swift b/novawallet/Common/DataProvider/Sources/Governance/ReferendumMetadataDetailsProviderSource.swift new file mode 100644 index 0000000000..3ad7d2956e --- /dev/null +++ b/novawallet/Common/DataProvider/Sources/Governance/ReferendumMetadataDetailsProviderSource.swift @@ -0,0 +1,97 @@ +import Foundation +import RobinHood +import SubstrateSdk + +final class ReferendumMetadataDetailsProviderSource { + typealias Model = ReferendumMetadataLocal + + let chainId: ChainModel.Id + let referendumId: ReferendumIdLocal + let operationFactory: PolkassemblyOperationFactoryProtocol + let repository: AnyDataProviderRepository + let operationQueue: OperationQueue + + init( + chainId: ChainModel.Id, + referendumId: ReferendumIdLocal, + operationFactory: PolkassemblyOperationFactoryProtocol, + repository: AnyDataProviderRepository, + operationQueue: OperationQueue + ) { + self.chainId = chainId + self.referendumId = referendumId + self.operationFactory = operationFactory + self.repository = repository + self.operationQueue = operationQueue + } +} + +extension ReferendumMetadataDetailsProviderSource: StreamableSourceProtocol { + func fetchHistory( + runningIn queue: DispatchQueue?, + commitNotificationBlock: ((Result?) -> Void)? + ) { + guard let closure = commitNotificationBlock else { + return + } + + let result: Result = Result.success(0) + + if let queue = queue { + queue.async { + closure(result) + } + } else { + closure(result) + } + } + + func refresh( + runningIn queue: DispatchQueue?, + commitNotificationBlock: ((Result?) -> Void)? + ) { + + let remoteFetchOperation = operationFactory.createDetailsOperation(for: referendumId) + + let identifier = ReferendumMetadataLocal.identifier(from: chainId, referendumId: referendumId) + let saveOperation = repository.saveOperation({ + let optItem = try remoteFetchOperation.extractNoCancellableResultData() + if let item = optItem { + return [item] + } else { + return [] + } + }, { + let optItem = try remoteFetchOperation.extractNoCancellableResultData() + + if optItem == nil { + return [identifier] + } else { + return [] + } + }) + + saveOperation.addDependency(remoteFetchOperation) + + saveOperation.completionBlock = { + do { + try saveOperation.extractNoCancellableResultData() + + let item = try remoteFetchOperation.extractNoCancellableResultData() + let count = item != nil ? 1 : 0 + + dispatchInQueueWhenPossible(queue) { + commitNotificationBlock?(.success(count)) + } + } catch { + dispatchInQueueWhenPossible(queue) { + commitNotificationBlock?(.failure(error)) + } + } + } + + let operations = [remoteFetchOperation, saveOperation] + + operationQueue.addOperations(operations, waitUntilFinished: false) + } +} diff --git a/novawallet/Common/DataProvider/Sources/Governance/ReferendumsMetadataPreviewProviderSource.swift b/novawallet/Common/DataProvider/Sources/Governance/ReferendumsMetadataPreviewProviderSource.swift new file mode 100644 index 0000000000..43e07a2df6 --- /dev/null +++ b/novawallet/Common/DataProvider/Sources/Governance/ReferendumsMetadataPreviewProviderSource.swift @@ -0,0 +1,97 @@ +import Foundation +import RobinHood +import SubstrateSdk + +final class ReferendumsMetadataPreviewProviderSource { + typealias Model = ReferendumMetadataLocal + + let operationFactory: PolkassemblyOperationFactoryProtocol + let repository: AnyDataProviderRepository + let operationQueue: OperationQueue + + init( + operationFactory: PolkassemblyOperationFactoryProtocol, + repository: AnyDataProviderRepository, + operationQueue: OperationQueue + ) { + self.operationFactory = operationFactory + self.repository = repository + self.operationQueue = operationQueue + } +} + +extension ReferendumsMetadataPreviewProviderSource: StreamableSourceProtocol { + func fetchHistory( + runningIn queue: DispatchQueue?, + commitNotificationBlock: ((Result?) -> Void)? + ) { + guard let closure = commitNotificationBlock else { + return + } + + let result: Result = Result.success(0) + + if let queue = queue { + queue.async { + closure(result) + } + } else { + closure(result) + } + } + + func refresh( + runningIn queue: DispatchQueue?, + commitNotificationBlock: ((Result?) -> Void)? + ) { + let remoteFetchOperation = operationFactory.createPreviewsOperation() + let localFetchOperation = repository.fetchAllOperation(with: RepositoryFetchOptions()) + + let changesOperation = ClosureOperation<[ReferendumMetadataLocal]> { + let localItems = try localFetchOperation.extractNoCancellableResultData().reduceToDict() + let remoteItems = try remoteFetchOperation.extractNoCancellableResultData() + + return remoteItems.map { remoteItem in + let localItem = localItems[remoteItem.identifier] + + return ReferendumMetadataLocal( + chainId: remoteItem.chainId, + referendumId: remoteItem.referendumId, + title: remoteItem.title, + content: localItem?.content, + proposer: localItem?.proposer, + timeline: localItem?.timeline + ) + } + } + + changesOperation.addDependency(remoteFetchOperation) + changesOperation.addDependency(localFetchOperation) + + let saveOperation = repository.replaceOperation { + try changesOperation.extractNoCancellableResultData() + } + + saveOperation.addDependency(changesOperation) + + saveOperation.completionBlock = { + do { + try saveOperation.extractNoCancellableResultData() + + let count = try changesOperation.extractNoCancellableResultData().count + + dispatchInQueueWhenPossible(queue) { + commitNotificationBlock?(.success(count)) + } + } catch { + dispatchInQueueWhenPossible(queue) { + commitNotificationBlock?(.failure(error)) + } + } + } + + let operations = [remoteFetchOperation, localFetchOperation, changesOperation, saveOperation] + + operationQueue.addOperations(operations, waitUntilFinished: false) + } +} diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift index c43649d04a..f0b4d31d58 100644 --- a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift @@ -6,17 +6,32 @@ protocol GovMetadataLocalStorageSubscriber: AnyObject { var govMetadataLocalSubscriptionHandler: GovMetadataLocalStorageHandler { get } - func subscribeGovMetadata(for chain: ChainModel) -> AnySingleValueProvider + func subscribeGovernanceMetadata( + for chain: ChainModel + ) -> StreamableProvider? + + func subscribeGovernanceMetadata( + for chain: ChainModel, + referendumId: ReferendumIdLocal + ) -> AnySingleValueProvider } extension GovMetadataLocalStorageSubscriber { - func subscribeGovMetadata(for chain: ChainModel) -> AnySingleValueProvider { - let provider = govMetadataLocalSubscriptionFactory.getMetadataProvider(for: chain) + func subscribeGovernanceMetadata( + for chain: ChainModel + ) -> StreamableProvider? { + guard let provider = govMetadataLocalSubscriptionFactory.getMetadataProvider(for: chain) else { + return nil + } + + let updateClosure: ([DataProviderChange]) -> Void = { [weak self] changes in + + let items = changes.mergeToDict([:]).reduce(into: ReferendumMetadataMapping()) { + $0[$1.value.referendumId] = $1.value + } - let updateClosure: ([DataProviderChange]) -> Void = { [weak self] changes in - let result = changes.reduceToLastChange() self?.govMetadataLocalSubscriptionHandler.handleGovMetadata( - result: .success(result), + result: .success(items), chain: chain ) return @@ -27,9 +42,11 @@ extension GovMetadataLocalStorageSubscriber { return } - let options = DataProviderObserverOptions( + let options = StreamableProviderObserverOptions( alwaysNotifyOnRefresh: false, - waitsInProgressSyncOnAdd: false + waitsInProgressSyncOnAdd: false, + initialSize: 0, + refreshWhenEmpty: true ) provider.addObserver( diff --git a/novawallet/Common/Extension/Foundation/NSPredicate+Filter.swift b/novawallet/Common/Extension/Foundation/NSPredicate+Filter.swift index 793a0d6d32..cd0320b2f8 100644 --- a/novawallet/Common/Extension/Foundation/NSPredicate+Filter.swift +++ b/novawallet/Common/Extension/Foundation/NSPredicate+Filter.swift @@ -309,4 +309,12 @@ extension NSPredicate { return NSCompoundPredicate(andPredicateWithSubpredicates: [chainPredicate, accountPredicate]) } + + static func referendums(for chainId: ChainModel.Id) -> NSPredicate { + NSPredicate( + format: "%K == %@", + #keyPath(CDReferendumMetadata.chainId), + chainId + ) + } } diff --git a/novawallet/Common/Migration/SubstrateStorageVersion.swift b/novawallet/Common/Migration/SubstrateStorageVersion.swift index f140884cc1..8aaa68d99e 100644 --- a/novawallet/Common/Migration/SubstrateStorageVersion.swift +++ b/novawallet/Common/Migration/SubstrateStorageVersion.swift @@ -3,6 +3,7 @@ enum SubstrateStorageVersion: String, CaseIterable { case version2 = "SubstrateDataModel2" case version3 = "SubstrateDataModel3" case version4 = "SubstrateDataModel4" + case version5 = "SubstrateDataModel5" static var current: SubstrateStorageVersion { allCases.last! @@ -17,6 +18,8 @@ enum SubstrateStorageVersion: String, CaseIterable { case .version3: return .version4 case .version4: + return .version5 + case .version5: return nil } } diff --git a/novawallet/Common/Model/ChainRegistry/ChainModel.swift b/novawallet/Common/Model/ChainRegistry/ChainModel.swift index 5812e8f5ad..95f6841e81 100644 --- a/novawallet/Common/Model/ChainRegistry/ChainModel.swift +++ b/novawallet/Common/Model/ChainRegistry/ChainModel.swift @@ -21,6 +21,7 @@ struct ChainModel: Equatable, Codable, Hashable { let staking: ExternalApi? let history: ExternalApi? let crowdloans: ExternalApi? + let governance: ExternalApi? } struct Explorer: Codable, Hashable { @@ -123,11 +124,11 @@ struct ChainModel: Equatable, Codable, Hashable { options?.contains(where: { $0 == .governance || $0 == .governanceV1 }) ?? false } - var hasGov1: Bool { + var hasGovernanceV1: Bool { options?.contains(where: { $0 == .governanceV1 }) ?? false } - var hasGov2: Bool { + var hasGovernanceV2: Bool { options?.contains(where: { $0 == .governance }) ?? false } diff --git a/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift b/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift new file mode 100644 index 0000000000..a39bef0015 --- /dev/null +++ b/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift @@ -0,0 +1,164 @@ +import Foundation +import RobinHood +import SubstrateSdk + +protocol PolkassemblyOperationFactoryProtocol { + func createPreviewsOperation() -> BaseOperation<[ReferendumMetadataPreview]> + + func createDetailsOperation( + for referendumId: ReferendumIdLocal + ) -> BaseOperation +} + +final class PolkassemblyChainOperationFactory { + let chainId: ChainModel.Id + let url: URL + + init(chainId: ChainModel.Id, url: URL) { + self.chainId = chainId + self.url = url + } + + private func createPreviewQuery() -> String { + """ + { + posts( + where: {type: {id: {_eq: 2}}, onchain_link: {onchain_referendum_id: {_is_null: false}}} + ) { + title + onchain_link { + onchain_referendum_id + } + } + } + """ + } + + private func createDetailsQuery(for referendumId: ReferendumIdLocal) -> String { + """ + { + posts( + where: {onchain_link: {onchain_referendum_id: {_eq: \(referendumId)}}} + ) { + title + content + onchain_link { + onchain_referendum_id + proposer_address + onchain_referendum { + referendumStatus { + blockNumber { + number + } + status + } + } + } + } + } + """ + } + + private func createRequestFactory(for url: URL, query: String) -> NetworkRequestFactoryProtocol { + return BlockNetworkRequestFactory { + var request = URLRequest(url: url) + let info = JSON.dictionaryValue(["query": JSON.stringValue(query)]) + request.httpBody = try JSONEncoder().encode(info) + request.setValue( + HttpContentType.json.rawValue, + forHTTPHeaderField: HttpHeaderKey.contentType.rawValue + ) + request.httpMethod = HttpMethod.post.rawValue + return request + } + } + + private func createPreviewResultFactory( + for chainId: ChainModel.Id + ) -> AnyNetworkResultFactory<[ReferendumMetadataPreview]> { + AnyNetworkResultFactory<[ReferendumMetadataPreview]> { data in + let resultData = try JSONDecoder().decode(JSON.self, from: data) + let nodes = resultData.data?.posts?.arrayValue ?? [] + + return nodes.compactMap { remotePreview in + let title = remotePreview.title?.stringValue + + guard let referendumId = remotePreview.onchain_link? + .onchain_referendum_id?.unsignedIntValue else { + return nil + } + + return .init( + chainId: chainId, + referendumId: ReferendumIdLocal(referendumId), + title: title + ) + } + } + } + + private func createDetailsResultFactory( + for chainId: ChainModel.Id + ) -> AnyNetworkResultFactory { + AnyNetworkResultFactory { data in + let resultData = try JSONDecoder().decode(JSON.self, from: data) + guard let remoteDetails = resultData.data?.posts?.arrayValue?.first else { + return nil + } + + let title = remoteDetails.title?.stringValue + let content = remoteDetails.content?.stringValue + let onChainLink = remoteDetails.onchain_link + + guard let referendumId = onChainLink?.onchain_referendum_id?.unsignedIntValue else { + return nil + } + + let proposer = onChainLink?.proposer_address?.stringValue + + let remoteTimeline = onChainLink?.onchain_referendum?.referendumStatus?.arrayValue + + let timeline: [ReferendumMetadataLocal.TimelineItem]? + timeline = remoteTimeline?.compactMap { item in + guard + let block = item.blockNumber?.number?.unsignedIntValue, + let status = item.status?.stringValue else { + return nil + } + + return .init(block: BlockNumber(block), status: status) + } + + return .init( + chainId: chainId, + referendumId: ReferendumIdLocal(referendumId), + title: title, + content: content, + proposer: proposer, + timeline: timeline + ) + } + } +} + +extension PolkassemblyChainOperationFactory: PolkassemblyOperationFactoryProtocol { + func createPreviewsOperation() -> BaseOperation<[ReferendumMetadataPreview]> { + let query = createPreviewQuery() + let requestFactory = createRequestFactory(for: url, query: query) + let resultFactory = createPreviewResultFactory(for: chainId) + + return NetworkOperation(requestFactory: requestFactory, resultFactory: resultFactory) + } + + func createDetailsOperation( + for referendumId: ReferendumIdLocal + ) -> BaseOperation { + let query = createDetailsQuery(for: referendumId) + let requestFactory = createRequestFactory(for: url, query: query) + let resultFactory = createDetailsResultFactory(for: chainId) + + return NetworkOperation(requestFactory: requestFactory, resultFactory: resultFactory) + } + + +} diff --git a/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift b/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift index 8af73dbc3b..df3c6ad2b6 100644 --- a/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift +++ b/novawallet/Common/Storage/EntityToModel/ChainModelMapper.swift @@ -195,8 +195,21 @@ final class ChainModelMapper { crowdloans = nil } - if staking != nil || history != nil || crowdloans != nil { - return ChainModel.ExternalApiSet(staking: staking, history: history, crowdloans: crowdloans) + let governance: ChainModel.ExternalApi? + + if let type = entity.governanceApiType, let url = entity.governanceApiUrl { + governance = .init(type: type, url: url) + } else { + governance = nil + } + + if staking != nil || history != nil || crowdloans != nil || governance != nil { + return ChainModel.ExternalApiSet( + staking: staking, + history: history, + crowdloans: crowdloans, + governance: governance + ) } else { return nil } @@ -211,6 +224,35 @@ final class ChainModelMapper { entity.crowdloansApiType = apis?.crowdloans?.type entity.crowdloansApiUrl = apis?.crowdloans?.url + + entity.governanceApiType = apis?.governance?.type + entity.governanceApiUrl = apis?.governance?.url + } + + private func createChainOptions(from entity: CDChain) -> [ChainOptions]? { + var options: [ChainOptions] = [] + + if entity.isEthereumBased { + options.append(.ethereumBased) + } + + if entity.isTestnet { + options.append(.testnet) + } + + if entity.hasCrowdloans { + options.append(.crowdloans) + } + + if entity.hasGovernance { + options.append(.governance) + } + + if entity.hasGovernanceV1 { + options.append(.governanceV1) + } + + return !options.isEmpty ? options : nil } } @@ -240,31 +282,11 @@ extension ChainModelMapper: CoreDataMapperProtocol { types = nil } - var options: [ChainOptions] = [] - - if entity.isEthereumBased { - options.append(.ethereumBased) - } - - if entity.isTestnet { - options.append(.testnet) - } - - if entity.hasCrowdloans { - options.append(.crowdloans) - } - - if entity.hasGovernance { - options.append(.governance) - } - - if entity.hasGovernanceV1 { - options.append(.governanceV1) - } - let externalApiSet = createExternalApi(from: entity) let explorers = createExplorers(from: entity) + let options = createChainOptions(from: entity) + let additional: JSON? = try entity.additional.map { try jsonDecoder.decode(JSON.self, from: $0) } @@ -278,7 +300,7 @@ extension ChainModelMapper: CoreDataMapperProtocol { addressPrefix: UInt16(bitPattern: entity.addressPrefix), types: types, icon: entity.icon!, - options: options.isEmpty ? nil : options, + options: options, externalApi: externalApiSet, explorers: explorers, order: entity.order, @@ -302,8 +324,8 @@ extension ChainModelMapper: CoreDataMapperProtocol { entity.isEthereumBased = model.isEthereumBased entity.isTestnet = model.isTestnet entity.hasCrowdloans = model.hasCrowdloans - entity.hasGovernanceV1 = model.hasGov1 - entity.hasGovernance = model.hasGov2 + entity.hasGovernanceV1 = model.hasGovernanceV1 + entity.hasGovernance = model.hasGovernanceV2 entity.order = model.order entity.additional = try model.additional.map { try jsonEncoder.encode($0) diff --git a/novawallet/Common/Storage/EntityToModel/ReferendumMetadataMapper.swift b/novawallet/Common/Storage/EntityToModel/ReferendumMetadataMapper.swift new file mode 100644 index 0000000000..2afae834d7 --- /dev/null +++ b/novawallet/Common/Storage/EntityToModel/ReferendumMetadataMapper.swift @@ -0,0 +1,54 @@ +import Foundation +import RobinHood +import SubstrateSdk +import CoreData + +final class ReferendumMetadataMapper { + var entityIdentifierFieldName: String { #keyPath(CDReferendumMetadata.identifier) } + + typealias DataProviderModel = ReferendumMetadataLocal + typealias CoreDataEntity = CDReferendumMetadata +} + +extension ReferendumMetadataMapper: CoreDataMapperProtocol { + func transform(entity: CoreDataEntity) throws -> DataProviderModel { + let timeline: [ReferendumMetadataLocal.TimelineItem]? + + if let timelineData = entity.timeline { + timeline = try JSONDecoder().decode( + [ReferendumMetadataLocal.TimelineItem].self, + from: timelineData + ) + } else { + timeline = nil + } + + return ReferendumMetadataLocal( + chainId: entity.chainId!, + referendumId: ReferendumIdLocal(entity.referendumId), + title: entity.title, + content: entity.content, + proposer: entity.proposer, + timeline: timeline + ) + } + + func populate( + entity: CoreDataEntity, + from model: DataProviderModel, + using context: NSManagedObjectContext + ) throws { + entity.identifier = model.identifier + entity.chainId = model.chainId + entity.referendumId = Int32(model.referendumId) + entity.title = model.title + entity.content = model.content + entity.proposer = model.proposer + + if let timeline = model.timeline, !timeline.isEmpty { + entity.timeline = try JSONEncoder().encode(timeline) + } else { + entity.timeline = nil + } + } +} diff --git a/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion index 7cfd904579..29dcbb1506 100644 --- a/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion +++ b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - SubstrateDataModel4.xcdatamodel + SubstrateDataModel5.xcdatamodel diff --git a/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel5.xcdatamodel/contents b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel5.xcdatamodel/contents new file mode 100644 index 0000000000..2be33b8e20 --- /dev/null +++ b/novawallet/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel5.xcdatamodel/contents @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift b/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift index 9974f19480..f6ff9b1523 100644 --- a/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift +++ b/novawallet/Modules/Vote/Governance/Model/DemocracyDecidingFunctionProtocol.swift @@ -49,8 +49,8 @@ final class Gov1DecidingFunction { extension Gov1DecidingFunction: DemocracyDecidingFunctionProtocol { func calculateThreshold( - for ayes: BigUInt, - nays: BigUInt, + for _: BigUInt, + nays _: BigUInt, turnout: BigUInt, electorate: BigUInt ) -> Decimal? { diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceOffchainApi.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceOffchainApi.swift new file mode 100644 index 0000000000..7f25d54fcc --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceOffchainApi.swift @@ -0,0 +1,5 @@ +import Foundation + +enum GovernanceOffchainApi: String { + case polkassembly +} diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index b96c2c3beb..8e6cc9304e 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -63,7 +63,7 @@ final class GovernanceSharedState { let chainId = chain.chainId - if chain.hasGov2 { + if chain.hasGovernanceV2 { let operationFactory = Gov2OperationFactory( requestFactory: requestFactory, operationQueue: operationQueue @@ -82,7 +82,7 @@ final class GovernanceSharedState { requestFactory: requestFactory, unlocksCalculator: GovUnlocksCalculator() ) - } else if chain.hasGov1 { + } else if chain.hasGovernanceV1 { let operationFactory = Gov1OperationFactory( requestFactory: requestFactory, operationQueue: operationQueue @@ -105,9 +105,9 @@ final class GovernanceSharedState { } func createExtrinsicFactory(for chain: ChainModel) -> GovernanceExtrinsicFactoryProtocol? { - if chain.hasGov2 { + if chain.hasGovernanceV2 { return Gov2ExtrinsicFactory() - } else if chain.hasGov1 { + } else if chain.hasGovernanceV1 { return Gov1ExtrinsicFactory() } else { return nil @@ -115,12 +115,12 @@ final class GovernanceSharedState { } func createActionsDetailsFactory(for chain: ChainModel) -> ReferendumActionOperationFactoryProtocol? { - if chain.hasGov2 { + if chain.hasGovernanceV2 { return Gov2ActionOperationFactory( requestFactory: requestFactory, operationQueue: operationQueue ) - } else if chain.hasGov1 { + } else if chain.hasGovernanceV1 { let gov2ActionsFactory = Gov2ActionOperationFactory( requestFactory: requestFactory, operationQueue: operationQueue @@ -137,9 +137,9 @@ final class GovernanceSharedState { } func governanceId(for chain: ChainModel) -> String? { - if chain.hasGov2 { + if chain.hasGovernanceV2 { return ConvictionVoting.lockId - } else if chain.hasGov1 { + } else if chain.hasGovernanceV1 { return Democracy.lockId } else { return nil diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift index 94109caf2c..c9a5a7b7c7 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift @@ -1,6 +1,38 @@ import Foundation +import RobinHood -struct ReferendumMetadataLocal: Equatable, Codable { - let name: String - let details: String +struct ReferendumMetadataPreview: Equatable { + let chainId: String + let referendumId: ReferendumIdLocal + let title: String? +} + +struct ReferendumMetadataLocal: Equatable { + struct TimelineItem: Equatable, Codable { + let block: BlockNumber + let status: String + } + + let chainId: String + let referendumId: ReferendumIdLocal + let title: String? + let content: String? + let proposer: String? + let timeline: [TimelineItem]? +} + +extension ReferendumMetadataLocal: Identifiable { + static func identifier(from chainId: ChainModel.Id, referendumId: ReferendumIdLocal) -> String { + chainId + "-" + String(referendumId) + } + + var identifier: String { + Self.identifier(from: chainId, referendumId: referendumId) + } +} + +extension ReferendumMetadataPreview: Identifiable { + var identifier: String { + ReferendumMetadataLocal.identifier(from: chainId, referendumId: referendumId) + } } From 574177937c423e77ac3e7f99f805bebb0c15a184 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 9 Nov 2022 02:05:10 +0500 Subject: [PATCH 171/229] add subscription functions --- .../GovMetadataLocalStorageHandler.swift | 16 ++++- .../GovMetadataLocalStorageSubscriber.swift | 59 +++++++++++++++++-- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift index 544fe6042c..e9f7149aac 100644 --- a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift @@ -1,15 +1,27 @@ import Foundation protocol GovMetadataLocalStorageHandler: AnyObject { - func handleGovMetadata( + func handleGovernanceMetadataPreview( result: Result, chain: ChainModel ) + + func handleGovernanceMetadataDetails( + result: Result, + chain: ChainModel + referendumId: ReferendumIdLocal + ) } extension GovMetadataLocalStorageHandler { - func handleGovMetadata( + func handleGovernanceMetadataPreview( result _: Result, chain _: ChainModel ) {} + + func handleGovernanceMetadataDetails( + result: Result, + chain: ChainModel + referendumId: ReferendumIdLocal + ) {} } diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift index f0b4d31d58..8d6aa0dbbe 100644 --- a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift @@ -13,7 +13,7 @@ protocol GovMetadataLocalStorageSubscriber: AnyObject { func subscribeGovernanceMetadata( for chain: ChainModel, referendumId: ReferendumIdLocal - ) -> AnySingleValueProvider + ) -> AnySingleValueProvider? } extension GovMetadataLocalStorageSubscriber { @@ -24,13 +24,14 @@ extension GovMetadataLocalStorageSubscriber { return nil } - let updateClosure: ([DataProviderChange]) -> Void = { [weak self] changes in + let updateClosure: ([DataProviderChange]) -> Void + updateClosure = { [weak self] changes in let items = changes.mergeToDict([:]).reduce(into: ReferendumMetadataMapping()) { $0[$1.value.referendumId] = $1.value } - self?.govMetadataLocalSubscriptionHandler.handleGovMetadata( + self?.govMetadataLocalSubscriptionHandler.handleGovernanceMetadataPreview( result: .success(items), chain: chain ) @@ -38,7 +39,57 @@ extension GovMetadataLocalStorageSubscriber { } let failureClosure: (Error) -> Void = { [weak self] error in - self?.govMetadataLocalSubscriptionHandler.handleGovMetadata(result: .failure(error), chain: chain) + self?.govMetadataLocalSubscriptionHandler.handleGovernanceMetadataPreview( + result: .failure(error), + chain: chain + ) + return + } + + let options = StreamableProviderObserverOptions( + alwaysNotifyOnRefresh: false, + waitsInProgressSyncOnAdd: false, + initialSize: 0, + refreshWhenEmpty: true + ) + + provider.addObserver( + self, + deliverOn: .main, + executing: updateClosure, + failing: failureClosure, + options: options + ) + + return provider + } + + func subscribeGovernanceMetadata( + for chain: ChainModel, + referendumId: ReferendumIdLocal + ) -> AnySingleValueProvider? { + guard let provider = govMetadataLocalSubscriptionFactory.getMetadataProvider(for: chain) else { + return nil + } + + let updateClosure: ([DataProviderChange]) -> Void + updateClosure = { [weak self] changes in + let item = changes.reduceToLastChange() + + self?.govMetadataLocalSubscriptionHandler.handleGovernanceMetadataDetails( + result: .success(item), + chain: chain, + referendumId: referendumId + ) + return + } + + let failureClosure: (Error) -> Void = { [weak self] error in + self?.govMetadataLocalSubscriptionHandler.handleGovernanceMetadataDetails( + result: .failure(error), + chain: chain, + referendumId: referendumId + ) return } From 67e23656126c99d82965195275f308cfef8e4952 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 9 Nov 2022 09:40:22 +0500 Subject: [PATCH 172/229] add polkassembly data source --- .../GovMetadataLocalSubscriptionFactory.swift | 44 +++++++++---------- ...erendumMetadataDetailsProviderSource.swift | 3 +- .../GovMetadataLocalStorageHandler.swift | 8 ++-- .../GovMetadataLocalStorageSubscriber.swift | 10 +++-- .../Foundation/NSPredicate+Filter.swift | 16 +++++++ .../PolkassemblyOperationFactory.swift | 4 +- .../ReferendumMetadataMapper.swift | 2 +- .../Storage/SubstrateDataStorageFacade.swift | 2 +- .../Model/GovernanceSharedState.swift | 11 ++++- .../ReferendumDetailsInteractor.swift | 19 +++++--- .../Referendums/ReferendumsInteractor.swift | 15 +++++-- .../ReferendumMetadataViewModelFactory.swift | 4 +- 12 files changed, 89 insertions(+), 49 deletions(-) diff --git a/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift index 9c3385a512..5b9774d8d9 100644 --- a/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift +++ b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift @@ -26,6 +26,20 @@ final class GovMetadataLocalSubscriptionFactory { self.operationQueue = operationQueue self.logger = logger } + + private func createOperationFactory( + for apiType: GovernanceOffchainApi, + url: URL, + chainId: ChainModel.Id + ) -> PolkassemblyOperationFactoryProtocol { + switch apiType { + case .polkassembly: + return PolkassemblyChainOperationFactory( + chainId: chainId, + url: url + ) + } + } } extension GovMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { @@ -51,17 +65,10 @@ extension GovMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFacto let repository = storageFacade.createRepository( filter: NSPredicate.referendums(for: chainId), sortDescriptors: [], - mapper: AnyCoreDataMapper(mapper)) + mapper: AnyCoreDataMapper(mapper) + ) - let operationFactory: PolkassemblyOperationFactoryProtocol - - switch apiType { - case .polkassembly: - operationFactory = PolkassemblyChainOperationFactory( - chainId: chainId, - url: url - ) - } + let operationFactory = createOperationFactory(for: apiType, url: url, chainId: chainId) let source = ReferendumsMetadataPreviewProviderSource( operationFactory: operationFactory, @@ -116,19 +123,12 @@ extension GovMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFacto let mapper = ReferendumMetadataMapper() let repository = storageFacade.createRepository( - filter: NSPredicate.referendums(for: chainId), + filter: NSPredicate.referendums(for: chainId, referendumId: referendumId), sortDescriptors: [], - mapper: AnyCoreDataMapper(mapper)) - - let operationFactory: PolkassemblyOperationFactoryProtocol + mapper: AnyCoreDataMapper(mapper) + ) - switch apiType { - case .polkassembly: - operationFactory = PolkassemblyChainOperationFactory( - chainId: chainId, - url: url - ) - } + let operationFactory = createOperationFactory(for: apiType, url: url, chainId: chainId) let source = ReferendumMetadataDetailsProviderSource( chainId: chainId, @@ -143,7 +143,7 @@ extension GovMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFacto mapper: AnyCoreDataMapper(mapper), predicate: { entity in chainId == entity.chainId && - referendumId == entity.referendumId + referendumId == entity.referendumId } ) diff --git a/novawallet/Common/DataProvider/Sources/Governance/ReferendumMetadataDetailsProviderSource.swift b/novawallet/Common/DataProvider/Sources/Governance/ReferendumMetadataDetailsProviderSource.swift index 3ad7d2956e..ee19837547 100644 --- a/novawallet/Common/DataProvider/Sources/Governance/ReferendumMetadataDetailsProviderSource.swift +++ b/novawallet/Common/DataProvider/Sources/Governance/ReferendumMetadataDetailsProviderSource.swift @@ -50,14 +50,13 @@ extension ReferendumMetadataDetailsProviderSource: StreamableSourceProtocol { runningIn queue: DispatchQueue?, commitNotificationBlock: ((Result?) -> Void)? ) { - let remoteFetchOperation = operationFactory.createDetailsOperation(for: referendumId) let identifier = ReferendumMetadataLocal.identifier(from: chainId, referendumId: referendumId) let saveOperation = repository.saveOperation({ let optItem = try remoteFetchOperation.extractNoCancellableResultData() if let item = optItem { - return [item] + return [item] } else { return [] } diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift index e9f7149aac..44c3170361 100644 --- a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift @@ -8,7 +8,7 @@ protocol GovMetadataLocalStorageHandler: AnyObject { func handleGovernanceMetadataDetails( result: Result, - chain: ChainModel + chain: ChainModel, referendumId: ReferendumIdLocal ) } @@ -20,8 +20,8 @@ extension GovMetadataLocalStorageHandler { ) {} func handleGovernanceMetadataDetails( - result: Result, - chain: ChainModel - referendumId: ReferendumIdLocal + result _: Result, + chain _: ChainModel, + referendumId _: ReferendumIdLocal ) {} } diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift index 8d6aa0dbbe..433d7ac988 100644 --- a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift @@ -13,7 +13,7 @@ protocol GovMetadataLocalStorageSubscriber: AnyObject { func subscribeGovernanceMetadata( for chain: ChainModel, referendumId: ReferendumIdLocal - ) -> AnySingleValueProvider? + ) -> StreamableProvider? } extension GovMetadataLocalStorageSubscriber { @@ -67,8 +67,12 @@ extension GovMetadataLocalStorageSubscriber { func subscribeGovernanceMetadata( for chain: ChainModel, referendumId: ReferendumIdLocal - ) -> AnySingleValueProvider? { - guard let provider = govMetadataLocalSubscriptionFactory.getMetadataProvider(for: chain) else { + ) -> StreamableProvider? { + guard + let provider = govMetadataLocalSubscriptionFactory.getMetadataProvider( + for: chain, + referendumId: referendumId + ) else { return nil } diff --git a/novawallet/Common/Extension/Foundation/NSPredicate+Filter.swift b/novawallet/Common/Extension/Foundation/NSPredicate+Filter.swift index cd0320b2f8..8d46b74259 100644 --- a/novawallet/Common/Extension/Foundation/NSPredicate+Filter.swift +++ b/novawallet/Common/Extension/Foundation/NSPredicate+Filter.swift @@ -317,4 +317,20 @@ extension NSPredicate { chainId ) } + + static func referendums(for chainId: ChainModel.Id, referendumId: ReferendumIdLocal) -> NSPredicate { + let chainPredicate = NSPredicate( + format: "%K == %@", + #keyPath(CDReferendumMetadata.chainId), + chainId + ) + + let referendumPredicate = NSPredicate( + format: "%K == %d", + #keyPath(CDReferendumMetadata.referendumId), + referendumId + ) + + return NSCompoundPredicate(andPredicateWithSubpredicates: [chainPredicate, referendumPredicate]) + } } diff --git a/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift b/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift index a39bef0015..9e3657fe69 100644 --- a/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift +++ b/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift @@ -60,7 +60,7 @@ final class PolkassemblyChainOperationFactory { } private func createRequestFactory(for url: URL, query: String) -> NetworkRequestFactoryProtocol { - return BlockNetworkRequestFactory { + BlockNetworkRequestFactory { var request = URLRequest(url: url) let info = JSON.dictionaryValue(["query": JSON.stringValue(query)]) request.httpBody = try JSONEncoder().encode(info) @@ -159,6 +159,4 @@ extension PolkassemblyChainOperationFactory: PolkassemblyOperationFactoryProtoco return NetworkOperation(requestFactory: requestFactory, resultFactory: resultFactory) } - - } diff --git a/novawallet/Common/Storage/EntityToModel/ReferendumMetadataMapper.swift b/novawallet/Common/Storage/EntityToModel/ReferendumMetadataMapper.swift index 2afae834d7..ca15c8d5dd 100644 --- a/novawallet/Common/Storage/EntityToModel/ReferendumMetadataMapper.swift +++ b/novawallet/Common/Storage/EntityToModel/ReferendumMetadataMapper.swift @@ -36,7 +36,7 @@ extension ReferendumMetadataMapper: CoreDataMapperProtocol { func populate( entity: CoreDataEntity, from model: DataProviderModel, - using context: NSManagedObjectContext + using _: NSManagedObjectContext ) throws { entity.identifier = model.identifier entity.chainId = model.chainId diff --git a/novawallet/Common/Storage/SubstrateDataStorageFacade.swift b/novawallet/Common/Storage/SubstrateDataStorageFacade.swift index 01736c6ce8..05986fd5aa 100644 --- a/novawallet/Common/Storage/SubstrateDataStorageFacade.swift +++ b/novawallet/Common/Storage/SubstrateDataStorageFacade.swift @@ -4,7 +4,7 @@ import CoreData enum SubstrateStorageParams { static let databaseName = "SubstrateDataModel.sqlite" static let modelDirectory: String = "SubstrateDataModel.momd" - static let modelVersion: SubstrateStorageVersion = .version4 + static let modelVersion: SubstrateStorageVersion = .version5 static let storageDirectoryURL: URL = { let baseURL = FileManager.default.urls( diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index 8e6cc9304e..38634220f1 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -26,11 +26,18 @@ final class GovernanceSharedState { remoteFactory: StorageKeyFactory(), operationManager: OperationManager(operationQueue: OperationManagerFacade.sharedDefaultQueue) ), - operationQueue: OperationQueue = OperationManagerFacade.sharedDefaultQueue + operationQueue: OperationQueue = OperationManagerFacade.sharedDefaultQueue, + logger: LoggerProtocol = Logger.shared ) { self.chainRegistry = chainRegistry settings = GovernanceChainSettings(chainRegistry: chainRegistry, settings: internalSettings) - govMetadataLocalSubscriptionFactory = GovMetadataLocalSubscriptionFactory(storageFacade: substrateStorageFacade) + + govMetadataLocalSubscriptionFactory = GovMetadataLocalSubscriptionFactory( + storageFacade: substrateStorageFacade, + operationQueue: operationQueue, + logger: logger + ) + self.blockTimeService = blockTimeService if let generalLocalSubscriptionFactory = generalLocalSubscriptionFactory { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index c8a8c1ed07..81e24ae612 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -23,7 +23,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? - private var metadataProvider: AnySingleValueProvider? + private var metadataProvider: StreamableProvider? private var blockNumberSubscription: AnyDataProvider? private var identitiesCancellable: CancellableCall? @@ -271,7 +271,13 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { subscribeReferendum() subscribeAccountVotes() - metadataProvider = subscribeGovMetadata(for: chain) + metadataProvider = subscribeGovernanceMetadata(for: chain, referendumId: referendum.index) + + if metadataProvider == nil { + presenter?.didReceiveMetadata(nil) + } else { + metadataProvider?.refresh() + } } } @@ -338,10 +344,13 @@ extension ReferendumDetailsInteractor: PriceLocalSubscriptionHandler, PriceLocal } extension ReferendumDetailsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataLocalStorageHandler { - func handleGovMetadata(result: Result, chain _: ChainModel) { + func handleGovernanceMetadataDetails( + result: Result, + chain _: ChainModel, + referendumId _: ReferendumIdLocal + ) { switch result { - case let .success(mapping): - let metadata = mapping?[referendum.index] + case let .success(metadata): presenter?.didReceiveMetadata(metadata) case let .failure(error): presenter?.didReceiveError(.metadataFailed(error)) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 89a3d32d62..023f7b1fe1 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -22,7 +22,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani private var priceProvider: AnySingleValueProvider? private var assetBalanceProvider: StreamableProvider? private var blockNumberSubscription: AnyDataProvider? - private var metadataProvider: AnySingleValueProvider? + private var metadataProvider: StreamableProvider? private lazy var localKeyFactory = LocalStorageKeyFactory() @@ -60,7 +60,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani private func clear() { clear(streamableProvider: &assetBalanceProvider) clear(singleValueProvider: &priceProvider) - clear(singleValueProvider: &metadataProvider) + clear(streamableProvider: &metadataProvider) clearBlockTimeService() clearSubscriptionFactory() @@ -167,7 +167,11 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani } private func subscribeToMetadata(for chain: ChainModel) { - metadataProvider = subscribeGovMetadata(for: chain) + metadataProvider = subscribeGovernanceMetadata(for: chain) + + if metadataProvider == nil { + presenter?.didReceiveReferendumsMetadata(nil) + } } private func handleChainChange(for newChain: ChainModel) { @@ -399,7 +403,10 @@ extension ReferendumsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataL governanceState.govMetadataLocalSubscriptionFactory } - func handleGovMetadata(result: Result, chain: ChainModel) { + func handleGovernanceMetadataPreview( + result: Result, + chain: ChainModel + ) { guard let currentChain = governanceState.settings.value, currentChain.chainId == chain.chainId else { return } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift index e3c6712f02..745d56f30e 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift @@ -45,7 +45,7 @@ final class ReferendumMetadataViewModelFactory { extension ReferendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol { func createTitle(for referendum: ReferendumLocal, metadata: ReferendumMetadataLocal?, locale: Locale) -> String { - if let title = metadata?.name, !title.isEmpty { + if let title = metadata?.title, !title.isEmpty { return title } else { let index = indexFormatter.value(for: locale).string(from: referendum.index as NSNumber) @@ -58,7 +58,7 @@ extension ReferendumMetadataViewModelFactory: ReferendumMetadataViewModelFactory } func createDescription(for _: ReferendumLocal, metadata: ReferendumMetadataLocal?, locale: Locale) -> String { - if let description = metadata?.details, !description.isEmpty { + if let description = metadata?.content, !description.isEmpty { return description } else { return R.string.localizable.govReferendumDescriptionFallback(preferredLanguages: locale.rLanguages) From 3ca2b620d596a1def4887a72674d3f093e6737be Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 9 Nov 2022 10:40:09 +0500 Subject: [PATCH 173/229] extract proposer from polkassembly data --- .../GovMetadataLocalStorageHandler.swift | 5 ++- .../GovMetadataLocalStorageSubscriber.swift | 7 +--- .../Model/ReferendumMetadataLocal.swift | 4 ++ .../ReferendumDetailsInteractor.swift | 21 ++--------- .../ReferendumDetailsPresenter.swift | 37 +++++++++++++++++-- .../ReferendumDetailsProtocols.swift | 2 +- .../Referendums/ReferendumsInteractor.swift | 8 ++-- .../Referendums/ReferendumsPresenter.swift | 16 +++++++- .../Referendums/ReferendumsProtocols.swift | 3 +- 9 files changed, 66 insertions(+), 37 deletions(-) diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift index 44c3170361..0207ba74d3 100644 --- a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift @@ -1,8 +1,9 @@ import Foundation +import RobinHood protocol GovMetadataLocalStorageHandler: AnyObject { func handleGovernanceMetadataPreview( - result: Result, + result: Result<[DataProviderChange], Error>, chain: ChainModel ) @@ -15,7 +16,7 @@ protocol GovMetadataLocalStorageHandler: AnyObject { extension GovMetadataLocalStorageHandler { func handleGovernanceMetadataPreview( - result _: Result, + result _: Result<[DataProviderChange], Error>, chain _: ChainModel ) {} diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift index 433d7ac988..318d6e1007 100644 --- a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift @@ -26,13 +26,8 @@ extension GovMetadataLocalStorageSubscriber { let updateClosure: ([DataProviderChange]) -> Void updateClosure = { [weak self] changes in - - let items = changes.mergeToDict([:]).reduce(into: ReferendumMetadataMapping()) { - $0[$1.value.referendumId] = $1.value - } - self?.govMetadataLocalSubscriptionHandler.handleGovernanceMetadataPreview( - result: .success(items), + result: .success(changes), chain: chain ) return diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift index c9a5a7b7c7..7a1c553c07 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift @@ -19,6 +19,10 @@ struct ReferendumMetadataLocal: Equatable { let content: String? let proposer: String? let timeline: [TimelineItem]? + + func proposerAccountId(for chainFormat: ChainFormat) -> AccountId? { + try? proposer?.toAccountId(using: chainFormat) + } } extension ReferendumMetadataLocal: Identifiable { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 81e24ae612..51ae13db26 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -146,25 +146,15 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } - private func provideIdentities() { + private func provideIdentities(for accountIds: Set) { clear(cancellable: &identitiesCancellable) - var accountIds: [AccountId] = [] - - if let proposer = referendum.proposer { - accountIds.append(proposer) - } - - if let beneficiary = actionDetails?.amountSpendDetails?.beneficiary.accountId { - accountIds.append(beneficiary) - } - guard !accountIds.isEmpty else { presenter?.didReceiveIdentities([:]) return } - let accountIdsClosure: () throws -> [AccountId] = { accountIds } + let accountIdsClosure: () throws -> [AccountId] = { Array(accountIds) } let wrapper = identityOperationFactory.createIdentityWrapper( for: accountIdsClosure, @@ -248,8 +238,6 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { self?.actionDetails = actionDetails self?.presenter?.didReceiveActionDetails(actionDetails) - - self?.provideIdentities() } catch { self?.presenter?.didReceiveError(.actionDetailsFailed(error)) } @@ -285,7 +273,6 @@ extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol func setup() { makeSubscriptions() updateActionDetails() - provideIdentities() provideDApps() } @@ -301,8 +288,8 @@ extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol updateActionDetails() } - func refreshIdentities() { - provideIdentities() + func refreshIdentities(for accountIds: Set) { + provideIdentities(for: accountIds) } func remakeSubscriptions() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 378ae43a10..1ccdcc258d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -92,8 +92,10 @@ final class ReferendumDetailsPresenter { private func provideTitleViewModel() { let accountViewModel: DisplayAddressViewModel? + let optProposer = referendum.proposer ?? referendumMetadata?.proposerAccountId(for: chain.chainFormat) + if - let proposer = referendum.proposer, + let proposer = optProposer, let identities = identities, let address = try? proposer.toAddress(using: chain.chainFormat) { let displayAddress = DisplayAddress(address: address, username: identities[address]?.displayName ?? "") @@ -308,6 +310,24 @@ final class ReferendumDetailsPresenter { view?.didReceive(activeTimeViewModel: updatedViewModel) } + + private func refreshIdentities() { + var accountIds: Set = [] + + if let proposer = referendum.proposer { + accountIds.insert(proposer) + } + + if let beneficiary = actionDetails?.amountSpendDetails?.beneficiary.accountId { + accountIds.insert(beneficiary) + } + + if let proposer = referendumMetadata?.proposerAccountId(for: chain.chainFormat) { + accountIds.insert(proposer) + } + + interactor.refreshIdentities(for: accountIds) + } } extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { @@ -322,13 +342,16 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { } func showProposerDetails() { + let referendumProposer = try? referendum.proposer?.toAddress(using: chain.chainFormat) + let optAddress = referendumProposer ?? referendumMetadata?.proposer + guard - let proposerAddress = try? referendum.proposer?.toAddress(using: chain.chainFormat), + let address = optAddress, let view = view else { return } - wireframe.presentAccountOptions(from: view, address: proposerAddress, chain: chain, locale: selectedLocale) + wireframe.presentAccountOptions(from: view, address: address, chain: chain, locale: selectedLocale) } func showAyeVoters() { @@ -365,6 +388,8 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol provideVotingDetails() provideTitleViewModel() updateTimerIfNeeded() + + refreshIdentities() } func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) { @@ -373,6 +398,8 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol provideTitleViewModel() provideRequestedAmount() provideFullDetailsViewModel() + + refreshIdentities() } func didReceiveAccountVotes(_ votes: ReferendumAccountVoteLocal?) { @@ -386,6 +413,8 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol provideTitleViewModel() provideFullDetailsViewModel() + + refreshIdentities() } func didReceiveIdentities(_ identities: [AccountAddress: AccountIdentity]) { @@ -437,7 +466,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol } case .identitiesFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in - self?.interactor.refreshIdentities() + self?.refreshIdentities() } case .blockTimeFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 818ca0e8c4..18e659122d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -25,7 +25,7 @@ protocol ReferendumDetailsInteractorInputProtocol: AnyObject { func setup() func refreshBlockTime() func refreshActionDetails() - func refreshIdentities() + func refreshIdentities(for accountIds: Set) func refreshDApps() func remakeSubscriptions() } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 023f7b1fe1..0cfa5240d6 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -170,7 +170,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani metadataProvider = subscribeGovernanceMetadata(for: chain) if metadataProvider == nil { - presenter?.didReceiveReferendumsMetadata(nil) + presenter?.didReceiveReferendumsMetadata([]) } } @@ -404,7 +404,7 @@ extension ReferendumsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataL } func handleGovernanceMetadataPreview( - result: Result, + result: Result<[DataProviderChange], Error>, chain: ChainModel ) { guard let currentChain = governanceState.settings.value, currentChain.chainId == chain.chainId else { @@ -412,8 +412,8 @@ extension ReferendumsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataL } switch result { - case let .success(mapping): - presenter?.didReceiveReferendumsMetadata(mapping) + case let .success(changes): + presenter?.didReceiveReferendumsMetadata(changes) case let .failure(error): presenter?.didReceiveError(.metadataSubscriptionFailed(error)) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index ef966b81e6..9334a4c679 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -1,6 +1,7 @@ import Foundation import BigInt import SoraFoundation +import RobinHood final class ReferendumsPresenter { weak var view: ReferendumsViewProtocol? @@ -282,8 +283,19 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { } } - func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) { - referendumsMetadata = metadata + func didReceiveReferendumsMetadata(_ changes: [DataProviderChange]) { + let indexedReferendums = Array((referendumsMetadata ?? [:]).values).reduceToDict() + + referendumsMetadata = changes.reduce(into: referendumsMetadata ?? [:]) { accum, change in + switch change { + case let .insert(newItem), let .update(newItem): + accum[newItem.referendumId] = newItem + case let .delete(deletedIdentifier): + if let referendumId = indexedReferendums[deletedIdentifier]?.referendumId { + accum[referendumId] = nil + } + } + } updateReferendumsView() } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 031cee8349..56f12bb2c6 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -1,4 +1,5 @@ import Foundation +import RobinHood protocol ReferendumsViewProtocol: ControllerBackedProtocol { var presenter: ReferendumsPresenterProtocol? { get set } @@ -27,7 +28,7 @@ protocol ReferendumsInteractorInputProtocol: AnyObject { protocol ReferendumsInteractorOutputProtocol: AnyObject { func didReceiveReferendums(_ referendums: [ReferendumLocal]) - func didReceiveReferendumsMetadata(_ metadata: ReferendumMetadataMapping?) + func didReceiveReferendumsMetadata(_ changes: [DataProviderChange]) func didReceiveVoting(_ voting: CallbackStorageSubscriptionResult) func didReceiveSelectedChain(_ chain: ChainModel) func didReceiveAssetBalance(_ balance: AssetBalance?) From 47857d3f4f5789afadc25e9b0ca1f76cf8d1649f Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 9 Nov 2022 17:41:48 +0500 Subject: [PATCH 174/229] fix timeline --- .../PolkassemblyOperationFactory.swift | 2 +- .../Democracy/DemocracyVoteThreshold.swift | 2 +- .../Model/ReferendumMetadataLocal.swift | 7 ++ .../ReferendumDetailsPresenter.swift | 1 + .../ReferendumTimelineViewModelFactory.swift | 117 +++++++++++++----- 5 files changed, 95 insertions(+), 34 deletions(-) diff --git a/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift b/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift index 9e3657fe69..22df28891e 100644 --- a/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift +++ b/novawallet/Common/Network/Polkassembly/PolkassemblyOperationFactory.swift @@ -116,7 +116,7 @@ final class PolkassemblyChainOperationFactory { let proposer = onChainLink?.proposer_address?.stringValue - let remoteTimeline = onChainLink?.onchain_referendum?.referendumStatus?.arrayValue + let remoteTimeline = onChainLink?.onchain_referendum?.arrayValue?.first?.referendumStatus?.arrayValue let timeline: [ReferendumMetadataLocal.TimelineItem]? timeline = remoteTimeline?.compactMap { item in diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyVoteThreshold.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyVoteThreshold.swift index a63b1ab5e6..f69dbde546 100644 --- a/novawallet/Common/Substrate/Types/Democracy/DemocracyVoteThreshold.swift +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyVoteThreshold.swift @@ -20,7 +20,7 @@ extension Democracy { switch type { case "SuperMajorityApprove": self = .superMajorityApprove - case "superMajorityAgainst": + case "SuperMajorityAgainst": self = .superMajorityAgainst case "SimpleMajority": self = .simpleMajority diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift index 7a1c553c07..5efae07341 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumMetadataLocal.swift @@ -7,6 +7,13 @@ struct ReferendumMetadataPreview: Equatable { let title: String? } +enum ReferendumMetadataStatus: String { + case started = "Started" + case passed = "Passed" + case notPassed = "NotPassed" + case executed = "Executed" +} + struct ReferendumMetadataLocal: Equatable { struct TimelineItem: Equatable, Codable { let block: BlockNumber diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 1ccdcc258d..0204242b90 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -412,6 +412,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol self.referendumMetadata = referendumMetadata provideTitleViewModel() + provideTimelineViewModel() provideFullDetailsViewModel() refreshIdentities() diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift index a067dfc395..8b2ef6f996 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumTimelineViewModelFactory.swift @@ -42,11 +42,13 @@ final class ReferendumTimelineViewModelFactory { return timeFormatter.value(for: locale).string(from: date) } - private func makeCreatedViewModel( + private func makeTimeViewModel( + title: String, atBlock: BlockNumber?, currentBlock: BlockNumber, blockTime: BlockTime, - locale: Locale + locale: Locale, + isLast: Bool = false ) -> ReferendumTimelineView.Model { let subtitle: ReferendumTimelineView.StatusSubtitle? @@ -63,10 +65,21 @@ final class ReferendumTimelineViewModelFactory { subtitle = nil } - return .init( + return .init(title: title, subtitle: subtitle, isLast: isLast) + } + + private func makeCreatedViewModel( + atBlock: BlockNumber?, + currentBlock: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumTimelineView.Model { + makeTimeViewModel( title: R.string.localizable.govTimelineCreated(preferredLanguages: locale.rLanguages), - subtitle: subtitle, - isLast: false + atBlock: atBlock, + currentBlock: currentBlock, + blockTime: blockTime, + locale: locale ) } @@ -153,6 +166,23 @@ final class ReferendumTimelineViewModelFactory { ) } + private func createApproved( + atBlock: BlockNumber?, + currentBlock: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> ReferendumTimelineView.Model { + let title = createApprovedTitle(for: locale) + + return makeTimeViewModel( + title: title, + atBlock: atBlock, + currentBlock: currentBlock, + blockTime: blockTime, + locale: locale + ) + } + private func createApproved( referendum: ReferendumLocal, currentBlock: BlockNumber, @@ -200,17 +230,55 @@ final class ReferendumTimelineViewModelFactory { return .init(title: title, subtitle: subtitle, isLast: true) } + + private func createExecutedViewModels( + metadata: ReferendumMetadataLocal?, + currentBlock: BlockNumber, + blockTime: BlockTime, + locale: Locale + ) -> [ReferendumTimelineView.Model] { + let approvedBlock = metadata?.timeline?.first( + where: { $0.status == ReferendumMetadataStatus.passed.rawValue } + )?.block + + let approved = createApproved( + atBlock: approvedBlock, + currentBlock: currentBlock, + blockTime: blockTime, + locale: locale + ) + + let executedBlock = metadata?.timeline?.first( + where: { $0.status == ReferendumMetadataStatus.executed.rawValue } + )?.block + + let executedTitle = R.string.localizable.governanceReferendumsStatusExecuted( + preferredLanguages: locale.rLanguages + ).firstLetterCapitalized() + + let executed = makeTimeViewModel( + title: executedTitle, + atBlock: executedBlock, + currentBlock: currentBlock, + blockTime: blockTime, + locale: locale, + isLast: true + ) + + return [approved, executed] + } } extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactoryProtocol { + // swiftlint:disable:next function_body_length func createTimelineViewModel( for referendum: ReferendumLocal, - metadata _: ReferendumMetadataLocal?, + metadata: ReferendumMetadataLocal?, currentBlock: BlockNumber, blockDuration: UInt64, locale: Locale ) -> [ReferendumTimelineView.Model]? { - let createdAt: BlockNumber? + var createdAt: BlockNumber? let models: [ReferendumTimelineView.Model] @@ -240,8 +308,6 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory models = [deciding] case .approved: - createdAt = nil - let approved = createApproved( referendum: referendum, currentBlock: currentBlock, @@ -251,8 +317,6 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory models = [approved] case let .rejected(model): - createdAt = nil - let rejected = createVotedTerminal( status: R.string.localizable.governanceReferendumsStatusRejected(preferredLanguages: locale.rLanguages), atBlock: model.atBlock, @@ -263,8 +327,6 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory models = [rejected] case let .cancelled(model): - createdAt = nil - let cancelled = createVotedTerminal( status: R.string.localizable.governanceReferendumsStatusCancelled( preferredLanguages: locale.rLanguages @@ -277,8 +339,6 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory models = [cancelled] case let .killed(atBlock): - createdAt = nil - let killed = createVotedTerminal( status: R.string.localizable.governanceReferendumsStatusKilled(preferredLanguages: locale.rLanguages), atBlock: atBlock, @@ -289,8 +349,6 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory models = [killed] case let .timedOut(model): - createdAt = nil - let timedOut = createVotedTerminal( status: R.string.localizable.governanceReferendumsStatusTimedOut(preferredLanguages: locale.rLanguages), atBlock: model.atBlock, @@ -301,23 +359,18 @@ extension ReferendumTimelineViewModelFactory: ReferendumTimelineViewModelFactory models = [timedOut] case .executed: - createdAt = nil - - let approved = ReferendumTimelineView.Model( - title: createApprovedTitle(for: locale), - subtitle: nil, - isLast: false - ) - - let executed = ReferendumTimelineView.Model( - title: R.string.localizable.governanceReferendumsStatusExecuted( - preferredLanguages: locale.rLanguages - ).firstLetterCapitalized(), - subtitle: nil, - isLast: true + models = createExecutedViewModels( + metadata: metadata, + currentBlock: currentBlock, + blockTime: blockDuration, + locale: locale ) + } - models = [approved, executed] + if createdAt == nil { + createdAt = metadata?.timeline?.first( + where: { $0.status == ReferendumMetadataStatus.started.rawValue } + )?.block } let created = makeCreatedViewModel( From ab870bc226d6066fee408ba89d619ec6a46d2627 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 9 Nov 2022 17:57:24 +0500 Subject: [PATCH 175/229] fix tests --- .../Migration/Mappers/ChainModelMapperV2V3.swift | 11 ++++++++--- .../Migration/SubstrateStorageMigrationTests.swift | 10 +++++----- novawalletTests/Helper/ChainModelGenerator.swift | 7 ++++++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/novawalletTests/Common/Migration/Mappers/ChainModelMapperV2V3.swift b/novawalletTests/Common/Migration/Mappers/ChainModelMapperV2V3.swift index 084a371daa..8e8827d43b 100644 --- a/novawalletTests/Common/Migration/Mappers/ChainModelMapperV2V3.swift +++ b/novawalletTests/Common/Migration/Mappers/ChainModelMapperV2V3.swift @@ -4,7 +4,7 @@ import CoreData import RobinHood import SubstrateSdk -final class ChainModelMapperV2V3 { +final class ChainModelMapperV2V5 { var entityIdentifierFieldName: String { #keyPath(CDChain.chainId) } typealias DataProviderModel = ChainModel @@ -197,7 +197,12 @@ final class ChainModelMapperV2V3 { } if staking != nil || history != nil || crowdloans != nil { - return ChainModel.ExternalApiSet(staking: staking, history: history, crowdloans: crowdloans) + return ChainModel.ExternalApiSet( + staking: staking, + history: history, + crowdloans: crowdloans, + governance: nil + ) } else { return nil } @@ -215,7 +220,7 @@ final class ChainModelMapperV2V3 { } } -extension ChainModelMapperV2V3: CoreDataMapperProtocol { +extension ChainModelMapperV2V5: CoreDataMapperProtocol { func transform(entity: CDChain) throws -> ChainModel { let assets: [AssetModel] = try entity.assets?.compactMap { anyAsset in guard let asset = anyAsset as? CDAsset else { diff --git a/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift b/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift index 09aa881f6c..d04ef3931d 100644 --- a/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift +++ b/novawalletTests/Common/Migration/SubstrateStorageMigrationTests.swift @@ -15,7 +15,7 @@ final class SubstrateStorageMigrationTests: XCTestCase { let databaseName = SubstrateStorageParams.databaseName let modelDirectory = SubstrateStorageParams.modelDirectory var storeURL: URL { databaseDirectoryURL.appendingPathComponent(databaseName) } - let oldMapper = ChainModelMapperV2V3() + let oldMapper = ChainModelMapperV2V5() let mapper = ChainModelMapper() override func setUpWithError() throws { @@ -31,14 +31,14 @@ final class SubstrateStorageMigrationTests: XCTestCase { try removeDirectory(at: databaseDirectoryURL) } - func testMigrationVersion3ToVersion4() { + func testMigrationVersion4ToVersion5() { let timeout: TimeInterval = 5 let generatedChains = generateChainsWithTimeout(timeout) XCTAssertGreaterThan(generatedChains.count, 0) let migrator = SubstrateStorageMigrator(storeURL: storeURL, modelDirectory: modelDirectory, - model: .version4, + model: .version5, fileManager: FileManager.default) XCTAssertTrue(migrator.requiresMigration(), "Migration is not required") @@ -95,7 +95,7 @@ final class SubstrateStorageMigrationTests: XCTestCase { private func generateChains(completion: @escaping (Result<[ChainModel], Error>) -> Void) { let chains = ChainModelGenerator.generate(count: 5) - let dbService = createCoreDataService(for: .version3) + let dbService = createCoreDataService(for: .version4) dbService.performAsync { [unowned self] (context, error) in if let error = error { @@ -132,7 +132,7 @@ final class SubstrateStorageMigrationTests: XCTestCase { } private func fetchChains(completion: @escaping (Result<[ChainModel], Error>) -> Void) { - let dbService = createCoreDataService(for: .version4) + let dbService = createCoreDataService(for: .version5) dbService.performAsync { [unowned self] (context, error) in if let error = error { diff --git a/novawalletTests/Helper/ChainModelGenerator.swift b/novawalletTests/Helper/ChainModelGenerator.swift index 74838ecbe6..90f48ea8f3 100644 --- a/novawalletTests/Helper/ChainModelGenerator.swift +++ b/novawalletTests/Helper/ChainModelGenerator.swift @@ -289,7 +289,12 @@ enum ChainModelGenerator { } if crowdloanApi != nil || stakingApi != nil { - return ChainModel.ExternalApiSet(staking: stakingApi, history: nil, crowdloans: crowdloanApi) + return ChainModel.ExternalApiSet( + staking: stakingApi, + history: nil, + crowdloans: crowdloanApi, + governance: nil + ) } else { return nil } From 318a00012cf214a1efe2e9a471f5e145deadb9cc Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 10 Nov 2022 00:31:49 +0500 Subject: [PATCH 176/229] fetch dapps from json --- novawallet.xcodeproj/project.pbxproj | 8 +-- .../Common/Configs/ApplicationConfigs.swift | 9 +++ .../Governance/Model/GovernanceDApp.swift | 24 -------- .../Governance/Model/GovernanceDAppList.swift | 22 +++++++ .../ReferendumDetailsInteractor.swift | 58 ++++++++++--------- .../ReferendumDetailsPresenter.swift | 20 +++++-- .../ReferendumDetailsProtocols.swift | 8 ++- .../ReferendumDetailsViewFactory.swift | 6 +- .../ReferendumDetailsWireframe.swift | 11 ++++ 9 files changed, 101 insertions(+), 65 deletions(-) delete mode 100644 novawallet/Modules/Vote/Governance/Model/GovernanceDApp.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/GovernanceDAppList.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 28785162d2..95377d5981 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1595,6 +1595,7 @@ 849B563527A70DDE007D5528 /* ExtrinsicProcessor+Matching.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849B563427A70DDE007D5528 /* ExtrinsicProcessor+Matching.swift */; }; 849C066F2765140B00394C82 /* AnyCancellableCleaning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849C066E2765140B00394C82 /* AnyCancellableCleaning.swift */; }; 849C0671276516F900394C82 /* BaseOperation+Cancellable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849C0670276516F900394C82 /* BaseOperation+Cancellable.swift */; }; + 849D3220291C26BA00D25839 /* GovernanceDAppList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D321F291C26BA00D25839 /* GovernanceDAppList.swift */; }; 849D755B2756910A007726C3 /* RoundedView+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D755A2756910A007726C3 /* RoundedView+Style.swift */; }; 849D755D27577602007726C3 /* AccountExportPasswordViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D755C27577602007726C3 /* AccountExportPasswordViewLayout.swift */; }; 849DEBD425ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849DEBD325ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift */; }; @@ -2147,7 +2148,6 @@ 84F1D66B29051A730050F4E3 /* ReferendumLockReuseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66A29051A730050F4E3 /* ReferendumLockReuseViewModel.swift */; }; 84F1D66D29051F240050F4E3 /* ReferendumReuseLockModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */; }; 84F1D66F29066F740050F4E3 /* ReferendumVotesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */; }; - 84F1D67129068F810050F4E3 /* GovernanceDApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F1D67029068F810050F4E3 /* GovernanceDApp.swift */; }; 84F1D67329069FFB0050F4E3 /* governanceDApps.json in Resources */ = {isa = PBXBuildFile; fileRef = 84F1D67229069FFB0050F4E3 /* governanceDApps.json */; }; 84F2FEFA25E797E8008338D5 /* StorageRequestFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FEF925E797E8008338D5 /* StorageRequestFactory.swift */; }; 84F2FEFF25E7ADE7008338D5 /* ValidatorPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2FEFE25E7ADE7008338D5 /* ValidatorPrefs.swift */; }; @@ -4581,6 +4581,7 @@ 849B563427A70DDE007D5528 /* ExtrinsicProcessor+Matching.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ExtrinsicProcessor+Matching.swift"; sourceTree = ""; }; 849C066E2765140B00394C82 /* AnyCancellableCleaning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyCancellableCleaning.swift; sourceTree = ""; }; 849C0670276516F900394C82 /* BaseOperation+Cancellable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseOperation+Cancellable.swift"; sourceTree = ""; }; + 849D321F291C26BA00D25839 /* GovernanceDAppList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceDAppList.swift; sourceTree = ""; }; 849D755A2756910A007726C3 /* RoundedView+Style.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RoundedView+Style.swift"; sourceTree = ""; }; 849D755C27577602007726C3 /* AccountExportPasswordViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountExportPasswordViewLayout.swift; sourceTree = ""; }; 849DEBD325ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmViewModel.swift; sourceTree = ""; }; @@ -5138,7 +5139,6 @@ 84F1D66A29051A730050F4E3 /* ReferendumLockReuseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumLockReuseViewModel.swift; sourceTree = ""; }; 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumReuseLockModel.swift; sourceTree = ""; }; 84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotesViewModel.swift; sourceTree = ""; }; - 84F1D67029068F810050F4E3 /* GovernanceDApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceDApp.swift; sourceTree = ""; }; 84F1D67229069FFB0050F4E3 /* governanceDApps.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = governanceDApps.json; sourceTree = ""; }; 84F2FEF925E797E8008338D5 /* StorageRequestFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageRequestFactory.swift; sourceTree = ""; }; 84F2FEFE25E7ADE7008338D5 /* ValidatorPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorPrefs.swift; sourceTree = ""; }; @@ -11740,11 +11740,11 @@ 8427495228FEB8C800B2B70B /* ReferendumNewVote.swift */, 84880C4329026C3E00CADB06 /* ReferendumDelegatingLocal.swift */, 84880C452902781E00CADB06 /* ReferendumVotingLocal.swift */, - 84F1D67029068F810050F4E3 /* GovernanceDApp.swift */, 843461E7290BF14400379936 /* ReferendumsSorting.swift */, 843461EB290D0D9400379936 /* GovernanceUnlockSchedule.swift */, 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */, 84C9CF3C291AF1B1002BF328 /* GovernanceOffchainApi.swift */, + 849D321F291C26BA00D25839 /* GovernanceDAppList.swift */, ); path = Model; sourceTree = ""; @@ -16629,6 +16629,7 @@ 845B0819291905CA005785D3 /* Gov1LockStateFactory.swift in Sources */, AE6F7FE82685F2F0002BBC3E /* ValidatorListFilterViewModelFactory.swift in Sources */, 84948C38287E0B4F00E6DD3E /* FilterImageProcessor.swift in Sources */, + 849D3220291C26BA00D25839 /* GovernanceDAppList.swift in Sources */, F022F1444E0F75CCA42F4648 /* YourValidatorListProtocols.swift in Sources */, 8493D0E326FF571D00A28008 /* PriceProviderFactory.swift in Sources */, F7EB8F835CFA7FC949EF4C22 /* YourValidatorListWireframe.swift in Sources */, @@ -17058,7 +17059,6 @@ 840B3D672899BFD200DA1DA9 /* QRScannerViewSettings.swift in Sources */, 577918C3D4AA22D887F605B5 /* ParaStkStakeSetupPresenter.swift in Sources */, 7050A26051FE62DB06B695F1 /* ParaStkStakeSetupInteractor.swift in Sources */, - 84F1D67129068F810050F4E3 /* GovernanceDApp.swift in Sources */, 0CD1F4D100ED82D137AB9834 /* ParaStkStakeSetupViewController.swift in Sources */, D9ECCCCF1449EFAFD0FA886E /* ParaStkStakeSetupViewLayout.swift in Sources */, A714CEAF7A86292E8D679056 /* ParaStkStakeSetupViewFactory.swift in Sources */, diff --git a/novawallet/Common/Configs/ApplicationConfigs.swift b/novawallet/Common/Configs/ApplicationConfigs.swift index d532093f61..feea4c6d04 100644 --- a/novawallet/Common/Configs/ApplicationConfigs.swift +++ b/novawallet/Common/Configs/ApplicationConfigs.swift @@ -22,6 +22,7 @@ protocol ApplicationConfigProtocol { var chainListURL: URL { get } var xcmTransfersURL: URL { get } var dAppsListURL: URL { get } + var governanceDAppsListURL: URL { get } var commonTypesURL: URL { get } var learnPayoutURL: URL { get } var learnControllerAccountURL: URL { get } @@ -143,6 +144,14 @@ extension ApplicationConfig: ApplicationConfigProtocol { #endif } + var governanceDAppsListURL: URL { + #if F_RELEASE + URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/governance/dapps.json")! + #else + URL(string: "https://raw.githubusercontent.com/nova-wallet/nova-utils/master/governance/dapps_dev.json")! + #endif + } + var canDebugDApp: Bool { #if F_RELEASE false diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceDApp.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceDApp.swift deleted file mode 100644 index dfad823668..0000000000 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceDApp.swift +++ /dev/null @@ -1,24 +0,0 @@ -import Foundation -import SoraFoundation - -struct GovernanceDApp: Codable { - struct Params: Codable { - let network: String - let index: ReferendumIdLocal - } - - let name: String - let subtitle: String - let icon: URL - let urlTemplate: String - - func url(for chain: ChainModel, referendumIndex: ReferendumIdLocal) throws -> URL { - // TODO: move to chain.json to make to reliable - let params = Params( - network: chain.name.lowercased(), - index: referendumIndex - ) - - return try EndpointBuilder(urlTemplate: urlTemplate).buildURL(with: params) - } -} diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceDAppList.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceDAppList.swift new file mode 100644 index 0000000000..dc632a41e5 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceDAppList.swift @@ -0,0 +1,22 @@ +import Foundation +import SoraFoundation + +enum GovernanceDApps { + struct DApp: Codable, Equatable { + let title: String + let details: String + let url: String + let icon: URL + + func extractFullUrl(for referendumIndex: ReferendumIdLocal) throws -> URL { + try EndpointBuilder(urlTemplate: url).buildParameterURL(String(referendumIndex)) + } + } + + struct Item: Codable, Equatable { + let chainId: String + let dapps: [DApp] + } +} + +typealias GovernanceDAppList = [GovernanceDApps.Item] diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 51ae13db26..72173a6643 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -19,7 +19,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol let referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol - let dAppsRepository: JsonFileRepository<[GovernanceDApp]> + let dAppsProvider: AnySingleValueProvider let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? @@ -44,7 +44,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol, referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, - dAppsRepository: JsonFileRepository<[GovernanceDApp]>, + dAppsProvider: AnySingleValueProvider, currencyManager: CurrencyManagerProtocol, operationQueue: OperationQueue ) { @@ -60,7 +60,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { self.blockTimeService = blockTimeService self.govMetadataLocalSubscriptionFactory = govMetadataLocalSubscriptionFactory self.referendumsSubscriptionFactory = referendumsSubscriptionFactory - self.dAppsRepository = dAppsRepository + self.dAppsProvider = dAppsProvider self.operationQueue = operationQueue self.currencyManager = currencyManager } @@ -116,34 +116,38 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { } } - private func provideDApps() { - clear(cancellable: &dAppsCancellable) - - let wrapper = dAppsRepository.fetchOperationWrapper( - by: R.file.governanceDAppsJson(), - defaultValue: [] - ) + private func handleDAppsUpdate(_ updatedDApps: GovernanceDAppList) { + let dApps = updatedDApps.first(where: { $0.chainId == chain.chainId })?.dapps ?? [] + presenter?.didReceiveDApps(dApps) + } - wrapper.targetOperation.completionBlock = { [weak self] in - DispatchQueue.main.async { - guard self?.dAppsCancellable === wrapper else { - return - } + private func subscribeDApps() { + dAppsProvider.removeObserver(self) - self?.dAppsCancellable = nil + let options = DataProviderObserverOptions( + alwaysNotifyOnRefresh: false, + waitsInProgressSyncOnAdd: false + ) - do { - let dApps = try wrapper.targetOperation.extractNoCancellableResultData() - self?.presenter?.didReceiveDApps(dApps) - } catch { - self?.presenter?.didReceiveError(.dAppsFailed(error)) - } + let updateClosure: ([DataProviderChange]) -> Void = { [weak self] changes in + if let result = changes.reduceToLastChange() { + self?.handleDAppsUpdate(result) + } else { + self?.presenter?.didReceiveDApps([]) } } - dAppsCancellable = wrapper + let failureClosure: (Error) -> Void = { [weak self] error in + self?.presenter?.didReceiveError(.dAppsFailed(error)) + } - operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) + dAppsProvider.addObserver( + self, + deliverOn: .main, + executing: updateClosure, + failing: failureClosure, + options: options + ) } private func provideIdentities(for accountIds: Set) { @@ -273,11 +277,11 @@ extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol func setup() { makeSubscriptions() updateActionDetails() - provideDApps() + subscribeDApps() } - func refreshDApps() { - provideDApps() + func remakeDAppsSubscription() { + subscribeDApps() } func refreshBlockTime() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 0204242b90..8e0e423a29 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -28,7 +28,7 @@ final class ReferendumDetailsPresenter { private var price: PriceData? private var blockNumber: BlockNumber? private var blockTime: BlockTime? - private var dApps: [GovernanceDApp]? + private var dApps: [GovernanceDApps.DApp]? private lazy var iconGenerator = PolkadotIconGenerator() @@ -223,8 +223,8 @@ final class ReferendumDetailsPresenter { let viewModels = dApps.map { ReferendumDAppView.Model( icon: RemoteImageViewModel(url: $0.icon), - title: $0.name, - subtitle: $0.subtitle + title: $0.title, + subtitle: $0.details ) } @@ -362,7 +362,15 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { wireframe.showVoters(from: view, referendum: referendum, type: .nays) } - func opeDApp(at _: Int) {} + func opeDApp(at index: Int) { + guard + let dApp = dApps?[index], + let url = try? dApp.extractFullUrl(for: referendum.index) else { + return + } + + wireframe.showDApp(from: view, url: url) + } func readFullDescription() {} @@ -447,7 +455,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol updateTimerIfNeeded() } - func didReceiveDApps(_ dApps: [GovernanceDApp]) { + func didReceiveDApps(_ dApps: [GovernanceDApps.DApp]) { self.dApps = dApps provideDAppViewModel() @@ -475,7 +483,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol } case .dAppsFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in - self?.interactor.refreshDApps() + self?.interactor.remakeDAppsSubscription() } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 18e659122d..dcd178b1c7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -1,3 +1,5 @@ +import Foundation + protocol ReferendumDetailsViewProtocol: ControllerBackedProtocol { func didReceive(votingDetails: ReferendumVotingStatusDetailsView.Model) func didReceive(dAppModels: [ReferendumDAppView.Model]?) @@ -26,7 +28,7 @@ protocol ReferendumDetailsInteractorInputProtocol: AnyObject { func refreshBlockTime() func refreshActionDetails() func refreshIdentities(for accountIds: Set) - func refreshDApps() + func remakeDAppsSubscription() func remakeSubscriptions() } @@ -39,7 +41,7 @@ protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { func didReceivePrice(_ price: PriceData?) func didReceiveBlockNumber(_ blockNumber: BlockNumber) func didReceiveBlockTime(_ blockTime: BlockTime) - func didReceiveDApps(_ dApps: [GovernanceDApp]) + func didReceiveDApps(_ dApps: [GovernanceDApps.DApp]) func didReceiveError(_ error: ReferendumDetailsInteractorError) } @@ -59,4 +61,6 @@ protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, referendum: ReferendumLocal, type: ReferendumVotersType ) + + func showDApp(from view: ReferendumDetailsViewProtocol?, url: URL) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index abcf97b109..e28214dac3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -114,7 +114,9 @@ struct ReferendumDetailsViewFactory { emptyIdentitiesWhenNoStorage: true ) - let dAppsRepository = JsonFileRepository<[GovernanceDApp]>() + let dAppsUrl = ApplicationConfig.shared.governanceDAppsListURL + let dAppsProvider: AnySingleValueProvider = + JsonDataProviderFactory.shared.getJson(for: dAppsUrl) return ReferendumDetailsInteractor( referendum: referendum, @@ -129,7 +131,7 @@ struct ReferendumDetailsViewFactory { generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, govMetadataLocalSubscriptionFactory: state.govMetadataLocalSubscriptionFactory, referendumsSubscriptionFactory: subscriptionFactory, - dAppsRepository: dAppsRepository, + dAppsProvider: dAppsProvider, currencyManager: currencyManager, operationQueue: OperationManagerFacade.sharedDefaultQueue ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index 7888f06489..cff28e9685 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -60,4 +60,15 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { view?.controller.present(navigationController, animated: true) } + + func showDApp(from view: ReferendumDetailsViewProtocol?, url: URL) { + guard + let browser = DAppBrowserViewFactory.createView( + for: .query(string: url.absoluteString) + ) else { + return + } + + view?.controller.navigationController?.pushViewController(browser.controller, animated: true) + } } From 9a4ed759dc500cdfd1829c5f0825b49a316ccd2f Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 10 Nov 2022 10:03:08 +0500 Subject: [PATCH 177/229] fix conflicts --- .../ReferendumDetails/ReferendumDetailsPresenter.swift | 6 +++++- .../ReferendumDetails/ReferendumDetailsProtocols.swift | 6 +++++- .../ReferendumDetails/ReferendumDetailsWireframe.swift | 8 +++++--- .../ReferendumFullDescriptionViewFactory.swift | 4 +++- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index d297544d12..146cd99db0 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -373,7 +373,11 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { } func readFullDescription() { - wireframe.showFullDescription(from: view, referendum: referendum) + guard let metadata = referendumMetadata else { + return + } + + wireframe.showFullDescription(from: view, referendumMetadata: metadata) } func openFullDetails() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index b954716174..29b98d4453 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -62,6 +62,10 @@ protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, type: ReferendumVotersType ) - func showFullDescription(from: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal) + func showFullDescription( + from view: ReferendumDetailsViewProtocol?, + referendumMetadata: ReferendumMetadataLocal + ) + func showDApp(from view: ReferendumDetailsViewProtocol?, url: URL) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index 7a90bdde81..b23fdd2ef3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -61,11 +61,13 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { view?.controller.present(navigationController, animated: true) } - func showFullDescription(from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal) { + func showFullDescription( + from view: ReferendumDetailsViewProtocol?, + referendumMetadata: ReferendumMetadataLocal + ) { guard let fullDescriptionView = ReferendumFullDescriptionViewFactory.createView( - state: state, - referendum: referendum + for: referendumMetadata ) else { return } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift index 477a311fc0..296ac8a592 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift @@ -1,7 +1,9 @@ import Foundation struct ReferendumFullDescriptionViewFactory { - static func createView(state _: GovernanceSharedState, referendum _: ReferendumLocal) -> ReferendumFullDescriptionViewProtocol? { + static func createView( + for _: ReferendumMetadataLocal + ) -> ReferendumFullDescriptionViewProtocol? { let interactor = ReferendumFullDescriptionInteractor() let wireframe = ReferendumFullDescriptionWireframe() From 718663f13f355e169d1559bef7af971218bb2bc1 Mon Sep 17 00:00:00 2001 From: Gulnaz <666lynx666@mail.ru> Date: Thu, 10 Nov 2022 12:39:59 +0400 Subject: [PATCH 178/229] New fields in referendum full details (#465) * added missed fields * renaming * remove duplicate key from localizable strings --- .../ReferendumFullDetailsPresenter.swift | 15 ++++-- .../ReferendumFullDetailsProtocols.swift | 2 +- .../ReferendumFullDetailsViewController.swift | 4 +- .../ReferendumFullDetailsViewLayout.swift | 50 +++++++++++++----- .../ReferendumStateLocal+Presenter.swift | 52 ++++++++++++++++--- .../ReferendumFullDetailsViewModel.swift | 12 +++-- novawallet/en.lproj/Localizable.strings | 6 +++ novawallet/ru.lproj/Localizable.strings | 6 +++ 8 files changed, 115 insertions(+), 32 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index 5ebae00571..a22ad980f6 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -99,16 +99,20 @@ final class ReferendumFullDetailsPresenter { private func provideCurveAndHashViewModel() { guard - let approvalCurve = referendum.state.approvalCurve, - let supportCurve = referendum.state.supportCurve else { + let functionInfo = referendum.state.functionInfo(locale: selectedLocale), + let turnout = referendum.state.turnout, + let electorate = referendum.state.electorate, + let turnoutBalance = getBalanceViewModel(turnout, locale: selectedLocale), + let electorateBalance = getBalanceViewModel(electorate, locale: selectedLocale) else { return } let callHash = referendum.state.callHash - let model = ReferendumFullDetailsViewModel.CurveAndHash( - approveCurve: approvalCurve.displayName(for: selectedLocale), - supportCurve: supportCurve.displayName(for: selectedLocale), + let model = ReferendumFullDetailsViewModel.Voting( + functionInfo: functionInfo, + turnout: turnoutBalance, + electorate: electorateBalance, callHash: callHash ) @@ -187,6 +191,7 @@ extension ReferendumFullDetailsPresenter: ReferendumFullDetailsInteractorOutputP provideProposerViewModel() provideBeneficiaryViewModel() + provideCurveAndHashViewModel() } func didReceive(call: ReferendumActionLocal.Call?) { diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift index 55261f7268..6f0654fb3b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsProtocols.swift @@ -1,7 +1,7 @@ protocol ReferendumFullDetailsViewProtocol: ControllerBackedProtocol { func didReceive(proposer: ReferendumFullDetailsViewModel.Proposer?) func didReceive(beneficiary: ReferendumFullDetailsViewModel.Beneficiary?) - func didReceive(params: ReferendumFullDetailsViewModel.CurveAndHash?) + func didReceive(params: ReferendumFullDetailsViewModel.Voting?) func didReceive(json: String?) func didReceiveTooLongJson() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift index 702e07165f..f007483cc2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewController.swift @@ -68,8 +68,8 @@ extension ReferendumFullDetailsViewController: ReferendumFullDetailsViewProtocol ) } - func didReceive(params: ReferendumFullDetailsViewModel.CurveAndHash?) { - rootView.setCurveAndHash(viewModel: params, locale: selectedLocale) + func didReceive(params: ReferendumFullDetailsViewModel.Voting?) { + rootView.setVoting(viewModel: params, locale: selectedLocale) rootView.callHashCell?.addTarget( self, diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index 62bdd42d30..6c4578849f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -109,7 +109,7 @@ final class ReferendumFullDetailsViewLayout: UIView { updateLayout() } - func setCurveAndHash(viewModel: ReferendumFullDetailsViewModel.CurveAndHash?, locale: Locale) { + func setVoting(viewModel: ReferendumFullDetailsViewModel.Voting?, locale: Locale) { curveAndHashTableView?.clear() curveAndHashTableView = nil @@ -119,21 +119,19 @@ final class ReferendumFullDetailsViewLayout: UIView { insertView(tableView, afterOneOf: [beneficiaryTableView, proposerTableView]) curveAndHashTableView = tableView } - - let approveCurveCell = createTitleValueCell( - with: R.string.localizable.govApproveCurve(preferredLanguages: locale.rLanguages), - value: viewModel.approveCurve + createVotingCells(viewModel: viewModel.functionInfo, locale: locale).forEach { + curveAndHashTableView?.addArrangedSubview($0) + } + let turnoutCell = createBalanceCell( + with: R.string.localizable.govTurnout(preferredLanguages: locale.rLanguages), + viewModel: viewModel.turnout ) - - curveAndHashTableView?.addArrangedSubview(approveCurveCell) - - let supportCurveCell = createTitleValueCell( - with: R.string.localizable.govSupportCurve(preferredLanguages: locale.rLanguages), - value: viewModel.supportCurve + let elecorateCell = createBalanceCell( + with: R.string.localizable.govElectorate(preferredLanguages: locale.rLanguages), + viewModel: viewModel.electorate ) - - curveAndHashTableView?.addArrangedSubview(supportCurveCell) - + curveAndHashTableView?.addArrangedSubview(turnoutCell) + curveAndHashTableView?.addArrangedSubview(elecorateCell) if let callHash = viewModel.callHash { let callHashCell = createInfoCell( with: R.string.localizable.govCallHash(preferredLanguages: locale.rLanguages), @@ -214,6 +212,30 @@ final class ReferendumFullDetailsViewLayout: UIView { self.jsonView = jsonView } + private func createVotingCells( + viewModel: ReferendumFullDetailsViewModel.FunctionInfo, + locale: Locale + ) -> [StackTableViewCellProtocol] { + switch viewModel { + case let .supportAndVotes(approveCurve, supportCurve): + let approveCurveCell = createTitleValueCell( + with: R.string.localizable.govApproveCurve(preferredLanguages: locale.rLanguages), + value: approveCurve + ) + let supportCurveCell = createTitleValueCell( + with: R.string.localizable.govSupportCurve(preferredLanguages: locale.rLanguages), + value: supportCurve + ) + return [approveCurveCell, supportCurveCell] + case let .threshold(function): + let thresholdFunctionCell = createTitleValueCell( + with: R.string.localizable.govVoteThreshold(preferredLanguages: locale.rLanguages), + value: function + ) + return [thresholdFunctionCell] + } + } + private func insertView(_ view: UIView, afterOneOf subviews: [UIView?]) { if let optSubview = subviews.first(where: { $0 != nil }), let subview = optSubview { containerView.stackView.insertArranged(view: view, after: subview) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift index 7702b566c3..f98e8cf5b3 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift @@ -1,23 +1,43 @@ import Foundation +import BigInt extension ReferendumStateLocal { - var approvalCurve: Referenda.Curve? { + func functionInfo(locale: Locale) -> ReferendumFullDetailsViewModel.FunctionInfo? { switch voting { case let .supportAndVotes(model): - return model.approvalFunction?.curve - case .threshold: - return nil + guard let supportCurve = model.supportFunction?.curve, + let approvalCurve = model.approvalFunction?.curve else { + return nil + } + return .supportAndVotes( + approveCurve: approvalCurve.displayName(for: locale), + supportCurve: supportCurve.displayName(for: locale) + ) + case let .threshold(model): + let thresholdTypeName = model.thresholdFunction.thresholdType.displayName(for: locale) + return .threshold(function: thresholdTypeName) case .none: return nil } } - var supportCurve: Referenda.Curve? { + var electorate: BigUInt? { switch voting { case let .supportAndVotes(model): - return model.supportFunction?.curve - case .threshold: + return model.totalIssuance + case let .threshold(model): + return model.electorate + case .none: return nil + } + } + + var turnout: BigUInt? { + switch voting { + case let .supportAndVotes(model): + return model.support + case let .threshold(model): + return model.turnout case .none: return nil } @@ -65,3 +85,21 @@ extension Referenda.Curve { } } } + +extension Democracy.VoteThreshold { + func displayName(for locale: Locale) -> String { + switch self { + case .simpleMajority: + return R.string.localizable.govVoteTresholdFunctionSimpleMajority(preferredLanguages: locale.rLanguages) + case .superMajorityAgainst: + return R.string.localizable.govVoteTresholdFunctionSuperMajorityAgainst( + preferredLanguages: locale.rLanguages) + case .superMajorityApprove: + return R.string.localizable.govVoteTresholdFunctionSuperMajorityApprove( + preferredLanguages: locale.rLanguages) + case .unknown: + return R.string.localizable.govUnknown( + preferredLanguages: locale.rLanguages) + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ViewModel/ReferendumFullDetailsViewModel.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ViewModel/ReferendumFullDetailsViewModel.swift index 1612374ada..f24054b289 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ViewModel/ReferendumFullDetailsViewModel.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ViewModel/ReferendumFullDetailsViewModel.swift @@ -11,9 +11,15 @@ enum ReferendumFullDetailsViewModel { let amount: BalanceViewModelProtocol? } - struct CurveAndHash { - let approveCurve: String - let supportCurve: String + struct Voting { + let functionInfo: FunctionInfo + let turnout: BalanceViewModelProtocol + let electorate: BalanceViewModelProtocol let callHash: String? } + + enum FunctionInfo { + case supportAndVotes(approveCurve: String, supportCurve: String) + case threshold(function: String) + } } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 446040a889..7b85a9402f 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1064,6 +1064,9 @@ "gov.requested.amount" = "Requested amount"; "gov.approve.curve" = "Approve Curve"; "gov.support.curve" = "Support Curve"; +"gov.vote.threshold" = "Vote threshold"; +"gov.turnout" = "Turnout"; +"gov.electorate" = "Electorate"; "gov.call.hash" = "Call Hash"; "gov.parameters.json" = "Parameters JSON"; "common.copy" = "Copy"; @@ -1076,3 +1079,6 @@ "common.unlock" = "Unlock"; "common.unlockable" = "Unlockable"; "gov.remains.locked.suffix" = " remains locked in %@"; +"gov.vote.treshold.function.simpleMajority" = "Simple Majority"; +"gov.vote.treshold.function.superMajorityAgainst" = "Super Majority Against"; +"gov.vote.treshold.function.superMajorityApprove" = "Super Majority Approve"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index d3096dff3d..88ca4f6298 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1063,6 +1063,9 @@ "gov.deposit" = "Депозит"; "gov.beneficiary" = "Получатель"; "gov.requested.amount" = "Запрашиваемая сумма"; +"gov.fulldetails.threshold" = "Порог голосования"; +"gov.fulldetails.turnout" = "Явка"; +"gov.fulldetails.electorate" = "Электорат"; "gov.approve.curve" = "Кривая подтверждения"; "gov.support.curve" = "Кривая поддержки"; "gov.call.hash" = "Хэш вызова"; @@ -1077,3 +1080,6 @@ "common.unlock" = "Разблокировать"; "common.unlockable" = "Разблокируемые"; "gov.remains.locked.suffix" = " остаются заблокированны в %@"; +"gov.vote.treshold.function.simpleMajority" = "Простое большинство"; +"gov.vote.treshold.function.superMajorityAgainst" = "Супербольшинство против"; +"gov.vote.treshold.function.superMajorityApprove" = "Супербольшинство за"; From 19252ce2f7c378bc013d24a266f204a432f74b4c Mon Sep 17 00:00:00 2001 From: Gulnaz <666lynx666@mail.ru> Date: Thu, 10 Nov 2022 12:40:20 +0400 Subject: [PATCH 179/229] fix formatter (#464) --- novawallet/Common/Extension/Foundation/DateFormatter.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/novawallet/Common/Extension/Foundation/DateFormatter.swift b/novawallet/Common/Extension/Foundation/DateFormatter.swift index 59053916c6..b5d6705adb 100644 --- a/novawallet/Common/Extension/Foundation/DateFormatter.swift +++ b/novawallet/Common/Extension/Foundation/DateFormatter.swift @@ -51,6 +51,7 @@ extension DateComponentsFormatter { let dateFormatter = DateComponentsFormatter() dateFormatter.allowedUnits = [.hour, .minute, .second] dateFormatter.unitsStyle = .positional + dateFormatter.zeroFormattingBehavior = .pad dateFormatter.calendar = calendar return dateFormatter From cdaa968281d6a15d176427cc41b2d4c2563f22c6 Mon Sep 17 00:00:00 2001 From: Gulnaz <666lynx666@mail.ru> Date: Thu, 10 Nov 2022 12:47:45 +0400 Subject: [PATCH 180/229] Referendum list shimmering (#462) * added loading state for model * added calculation * cleanup * update corners * pr fixes --- .../View/CrowdloanTableViewCell.swift | 7 +- .../View/YourContributionsView.swift | 7 +- .../Referendums/ReferendumsPresenter.swift | 2 +- .../Referendums/ReferendumsViewManager.swift | 40 +++- .../Governance/View/ReferendumInfoView.swift | 17 +- .../View/ReferendumTableViewCell.swift | 222 +++++++++++++++++- .../Governance/View/VotingProgressView.swift | 11 +- .../ViewModel/ReferendumsModelFactory.swift | 12 + 8 files changed, 296 insertions(+), 22 deletions(-) diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableViewCell.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableViewCell.swift index a9434b7fc4..857ff1f2f6 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableViewCell.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/CrowdloanTableViewCell.swift @@ -250,12 +250,11 @@ extension CrowdloanTableViewCell: SkeletonableViewCell, SkeletonableView { } func updateLoadingState() { - guard let viewModel = viewModel, viewModel.value != nil else { + if viewModel?.isLoading == false { + stopLoadingIfNeeded() + } else { startLoadingIfNeeded() - return } - - stopLoadingIfNeeded() } // swiftlint:disable function_body_length diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/YourContributionsView.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/YourContributionsView.swift index 6eb2f1a98a..d61cebf1ec 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/YourContributionsView.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/View/YourContributionsView.swift @@ -169,12 +169,11 @@ extension YourContributionsView: SkeletonableView { } func updateLoadingState() { - guard let viewModel = viewModel, viewModel.value != nil else { + if viewModel?.isLoading == false { + stopLoadingIfNeeded() + } else { startLoadingIfNeeded() - return } - - stopLoadingIfNeeded() } func createSkeletons(for spaceSize: CGSize) -> [Skeletonable] { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index ef966b81e6..1b5dfe53f5 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -241,6 +241,7 @@ extension ReferendumsPresenter: ReferendumsPresenterProtocol { extension ReferendumsPresenter: VoteChildPresenterProtocol { func setup() { + view?.update(model: .init(sections: viewModelFactory.createLoadingViewModel())) interactor.setup() } @@ -304,7 +305,6 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { updateReferendumsView() updateTimeModels() - refreshUnlockSchedule() } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 38461aaf50..8572a68802 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -4,6 +4,8 @@ import UIKit final class ReferendumsViewManager: NSObject { private enum Constants { static let unlocksCellHeight: CGFloat = 52 + static let referendumCellMinimumHeight: CGFloat = 185 + static let headerMinimumHeight: CGFloat = 56 } let tableView: UITableView @@ -114,19 +116,45 @@ extension ReferendumsViewManager: UITableViewDelegate { } func tableView(_: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - if section > 0 { - return UITableView.automaticDimension - } else { + guard section > 0 else { return 0 } + let referendumsSection = section - 1 + let sectionModel = referendumsViewModel.sections[referendumsSection] + switch sectionModel { + case let .active(header, _), let .completed(header, _): + switch header { + case .loaded, .cached: + return UITableView.automaticDimension + case .loading: + return Constants.headerMinimumHeight + } + } } func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - if indexPath.section > 0 { - return UITableView.automaticDimension - } else { + guard indexPath.section > 0 else { return Constants.unlocksCellHeight } + let referendumsSection = indexPath.section - 1 + let sectionModel = referendumsViewModel.sections[referendumsSection] + switch sectionModel { + case let .active(_, cells), let .completed(_, cells): + switch cells[indexPath.row].viewModel { + case .loaded, .cached: + return UITableView.automaticDimension + case .loading: + return Constants.referendumCellMinimumHeight + } + } + } + + func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt _: IndexPath) { + (cell as? SkeletonableViewCell)?.updateLoadingState() + } + + func tableView(_: UITableView, willDisplayHeaderView view: UIView, forSection _: Int) { + (view as? SkeletonableView)?.updateLoadingState() } } diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift index 6b4b15ca37..6bd8443426 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumInfoView.swift @@ -33,7 +33,7 @@ final class ReferendumInfoView: UIView { private var trackImageViewModel: ImageViewModelProtocol? lazy var trackInformation: UIStackView = UIView.hStack( - spacing: 6, + spacing: Constants.trackInformationHorizontalSpace, [ trackNameView, numberLabel, @@ -54,7 +54,7 @@ final class ReferendumInfoView: UIView { private func setupLayout() { let content = UIView.vStack( - spacing: 8, + spacing: Constants.verticalSpace, [ UIView.hStack([ statusLabel, @@ -66,7 +66,7 @@ final class ReferendumInfoView: UIView { ] ) - content.setCustomSpacing(12, after: titleLabel) + content.setCustomSpacing(Constants.afterTitleLabelVerticalSpace, after: titleLabel) addSubview(content) content.snp.makeConstraints { @@ -74,11 +74,20 @@ final class ReferendumInfoView: UIView { } trackInformation.snp.makeConstraints { - $0.height.equalTo(22.0) + $0.height.equalTo(Constants.trackInformationHeight) } } } +extension ReferendumInfoView { + enum Constants { + static let verticalSpace: CGFloat = 8 + static let afterTitleLabelVerticalSpace: CGFloat = 12 + static let trackInformationHeight: CGFloat = 22 + static let trackInformationHorizontalSpace: CGFloat = 6 + } +} + extension ReferendumInfoView { struct Model { let status: Status diff --git a/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift b/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift index e0ad82fea9..87f16f8868 100644 --- a/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift +++ b/novawallet/Modules/Vote/Governance/View/ReferendumTableViewCell.swift @@ -1,9 +1,12 @@ import UIKit +import SoraUI final class ReferendumView: UIView { let referendumInfoView = ReferendumInfoView() let progressView = VotingProgressView() let yourVoteView = YourVotesView() + var skeletonView: SkrullableView? + private var viewModel: LoadableViewModelState? override init(frame: CGRect) { super.init(frame: frame) @@ -31,6 +34,14 @@ final class ReferendumView: UIView { $0.edges.equalToSuperview() } } + + override func layoutSubviews() { + super.layoutSubviews() + + if skeletonView == nil, viewModel?.isLoading == true { + updateLoadingState() + } + } } typealias ReferendumTableViewCell = BlurredTableViewCell @@ -51,7 +62,8 @@ extension ReferendumView { } func bind(viewModel: LoadableViewModelState) { - // TODO: Skeleton + self.viewModel = viewModel + guard let model = viewModel.value else { return } @@ -71,3 +83,211 @@ extension ReferendumView { } } } + +extension ReferendumView: SkeletonableView { + var skeletonSuperview: UIView { + self + } + + var hidingViews: [UIView] { + [ + referendumInfoView, + progressView, + yourVoteView + ] + } + + func updateLoadingState() { + if viewModel?.isLoading == false { + stopLoadingIfNeeded() + } else { + startLoadingIfNeeded() + } + } + + func createSkeletons(for spaceSize: CGSize) -> [Skeletonable] { + let (referendumInfoViewSkeletons, referendumInfoViewBottomViewMaxY) = + referendumInfoView.createSkeletons(on: self, contentInsets: .zero, spaceSize: spaceSize) + + let progressViewSkeletons = progressView.createSkeletons( + on: self, + contentInsets: .init(top: referendumInfoViewBottomViewMaxY, left: 0, bottom: 0, right: 0), + spaceSize: spaceSize + ) + + return referendumInfoViewSkeletons + progressViewSkeletons + } +} + +extension VotingProgressView { + // swiftlint:disable:next function_body_length + func createSkeletons( + on view: UIView, + contentInsets externalInsets: UIEdgeInsets, + spaceSize: CGSize + ) -> [SingleSkeleton] { + let contentInsets = UIEdgeInsets( + top: externalInsets.top + Constants.contentInsets.top, + left: externalInsets.left + Constants.contentInsets.left, + bottom: externalInsets.bottom + Constants.contentInsets.bottom, + right: externalInsets.right + Constants.contentInsets.right + ) + let tresholdSkeletonSize = CGSize(width: 121, height: 8) + let progressSkeletonHeight: CGFloat = 5 + let votingSkeletonSize = CGSize(width: 60, height: 8) + + let thresholdViewHeight = max(thresholdView.iconWidth, thresholdView.detailsLabel.font.lineHeight) + let thresholdSkeletonOffsetY = contentInsets.top + thresholdViewHeight / 2 - tresholdSkeletonSize.height / 2 + let thresholdSkeletonOffset = CGPoint( + x: contentInsets.left, + y: thresholdSkeletonOffsetY + ) + + let progressOffsetY = contentInsets.top + thresholdViewHeight + Constants.verticalSpace + let sliderHeight = slider.intrinsicContentSize.height + let progressSkeletonOffsetY = progressOffsetY + sliderHeight / 2 - progressSkeletonHeight / 2 + let progressHalfWidth = (spaceSize.width - contentInsets.left - contentInsets.right - 6) / 2 + + let progressSkeletonFirstPartOffset = CGPoint( + x: contentInsets.left, + y: progressSkeletonOffsetY + ) + let progressSkeletonSecondPartOffset = CGPoint( + x: progressSkeletonFirstPartOffset.x + progressHalfWidth + 6, + y: progressSkeletonOffsetY + ) + let progressSkeletonSize = CGSize(width: progressHalfWidth, height: progressSkeletonHeight) + let votingSkeletonOffsetY = progressOffsetY + sliderHeight + Constants.verticalSpace + + ayeProgressLabel.font.lineHeight / 2 - votingSkeletonSize.height / 2 + let ayeVotingSkeletonOffset = CGPoint( + x: contentInsets.left, + y: votingSkeletonOffsetY + ) + let nayVotingSkeletonOffset = CGPoint( + x: spaceSize.width - contentInsets.right - votingSkeletonSize.width, + y: votingSkeletonOffsetY + ) + let progressCenterX = (progressSkeletonSecondPartOffset.x + progressSkeletonSize.width - + progressSkeletonFirstPartOffset.x) / 2 + let passVotingSkeletonOffset = CGPoint( + x: progressCenterX - votingSkeletonSize.width / 2, + y: votingSkeletonOffsetY + ) + + return [ + CGRect(origin: thresholdSkeletonOffset, size: tresholdSkeletonSize), + CGRect(origin: progressSkeletonFirstPartOffset, size: progressSkeletonSize), + CGRect(origin: progressSkeletonSecondPartOffset, size: progressSkeletonSize), + CGRect(origin: ayeVotingSkeletonOffset, size: votingSkeletonSize), + CGRect(origin: passVotingSkeletonOffset, size: votingSkeletonSize), + CGRect(origin: nayVotingSkeletonOffset, size: votingSkeletonSize) + ].map { + SingleSkeleton.createRow( + on: view, + containerView: view, + spaceSize: spaceSize, + offset: $0.origin, + size: $0.size + ) + } + } +} + +extension ReferendumInfoView { + // swiftlint:disable:next function_body_length + func createSkeletons(on view: UIView, contentInsets: UIEdgeInsets, spaceSize: CGSize) -> ( + skeletons: [SingleSkeleton], + bottomViewMaxY: CGFloat + ) { + let statusSkeletonSize = CGSize(width: 60, height: 12) + let timeSkeletonSize = CGSize(width: 116, height: 12) + let titleSkeletonSize = CGSize(width: 178, height: 12) + let trackNameSkeletonSize = CGSize(width: 121, height: 22) + let numberSkeletonSize = CGSize(width: 46, height: 22) + + let statusSkeletonOffsetY = contentInsets.top + statusLabel.font.lineHeight / 2 - statusSkeletonSize.height / 2 + + let statusSkeletonOffset = CGPoint( + x: contentInsets.left, + y: statusSkeletonOffsetY + ) + + let timeSkeletonOffsetY = contentInsets.top + timeView.detailsLabel.font.lineHeight / 2 - + timeSkeletonSize.height / 2 + let timeSkeletonOffset = CGPoint( + x: spaceSize.width - contentInsets.right - timeSkeletonSize.width, + y: timeSkeletonOffsetY + ) + + let titleOffsetY = contentInsets.top + statusLabel.font.lineHeight + Constants.verticalSpace + let titleSkeletonOffsetY: CGFloat = titleOffsetY + titleLabel.font.lineHeight / 2 - titleSkeletonSize.height / 2 + + let titleSkeletonOffset = CGPoint( + x: contentInsets.left, + y: titleSkeletonOffsetY + ) + let trackNameOffsetY = contentInsets.top + statusLabel.font.lineHeight + Constants.verticalSpace + + titleLabel.font.lineHeight + Constants.afterTitleLabelVerticalSpace + let trackNameSkeletonOffsetY = trackNameOffsetY + Constants.trackInformationHeight / 2 - + trackNameSkeletonSize.height / 2 + + let trackNameSkeletonOffset = CGPoint( + x: contentInsets.left, + y: trackNameSkeletonOffsetY + ) + + let numberSkeletonOffset = CGPoint( + x: trackNameSkeletonOffset.x + trackNameSkeletonSize.width + Constants.trackInformationHorizontalSpace, + y: trackNameSkeletonOffsetY + ) + + return ( + skeletons: [ + SingleSkeleton.createRow( + on: view, + containerView: view, + spaceSize: spaceSize, + offset: statusSkeletonOffset, + size: statusSkeletonSize + ), + SingleSkeleton.createRow( + on: view, + containerView: view, + spaceSize: spaceSize, + offset: timeSkeletonOffset, + size: timeSkeletonSize + ), + SingleSkeleton.createRow( + on: view, + containerView: view, + spaceSize: spaceSize, + offset: titleSkeletonOffset, + size: titleSkeletonSize + ), + SingleSkeleton.createRow( + on: view, + containerView: view, + spaceSize: spaceSize, + offset: trackNameSkeletonOffset, + size: trackNameSkeletonSize, + cornerRadii: .init( + width: 7 / trackNameSkeletonSize.width, + height: 7 / trackNameSkeletonSize.height + ) + ), + SingleSkeleton.createRow( + on: view, + containerView: view, + spaceSize: spaceSize, + offset: numberSkeletonOffset, + size: numberSkeletonSize, + cornerRadii: .init( + width: 7 / numberSkeletonSize.width, + height: 7 / numberSkeletonSize.height + ) + ) + ], + bottomViewMaxY: trackNameOffsetY + Constants.trackInformationHeight + ) + } +} diff --git a/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift index f12b2210a4..301d115093 100644 --- a/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift +++ b/novawallet/Modules/Vote/Governance/View/VotingProgressView.swift @@ -29,7 +29,7 @@ final class VotingProgressView: UIView { private func setupLayout() { let content = UIView.vStack( - spacing: 6, + spacing: Constants.verticalSpace, [ thresholdView, slider, @@ -46,11 +46,18 @@ final class VotingProgressView: UIView { addSubview(content) content.snp.makeConstraints { - $0.edges.equalToSuperview().inset(UIEdgeInsets(top: 16, left: 0, bottom: 0, right: 0)) + $0.edges.equalToSuperview().inset(Constants.contentInsets) } } } +extension VotingProgressView { + enum Constants { + static let verticalSpace: CGFloat = 6 + static let contentInsets = UIEdgeInsets(top: 16, left: 0, bottom: 0, right: 0) + } +} + extension VotingProgressView: BindableView { struct Model { let support: SupportModel? diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 35577f5a5b..ad36e0b321 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -26,6 +26,8 @@ protocol ReferendumsModelFactoryProtocol { chainInfo: ReferendumsModelFactoryInput.ChainInformation, selectedLocale: Locale ) -> ReferendumView.Model + + func createLoadingViewModel() -> [ReferendumsSection] } final class ReferendumsModelFactory { @@ -489,6 +491,16 @@ final class ReferendumsModelFactory { } extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { + func createLoadingViewModel() -> [ReferendumsSection] { + let cells: [ReferendumsCellViewModel] = (0 ..< 10).map { + ReferendumsCellViewModel( + referendumIndex: UInt($0), + viewModel: .loading + ) + } + return [ReferendumsSection.active(.loading, cells)] + } + func createSections(input: ReferendumsModelFactoryInput) -> [ReferendumsSection] { var active: [ReferendumsCellViewModel] = [] var completed: [ReferendumsCellViewModel] = [] From 1044b21d75ebff29c88e73d84c07f34bfbcce486 Mon Sep 17 00:00:00 2001 From: Gulnaz <666lynx666@mail.ru> Date: Thu, 10 Nov 2022 15:03:51 +0400 Subject: [PATCH 181/229] Show shimmering when user is changing chain (#467) * shimmering for chain switch * change priority * bugfix --- .../Vote/Governance/Referendums/ReferendumsPresenter.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index e68ddff9c0..59fbcbbded 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -68,7 +68,7 @@ final class ReferendumsPresenter { timeModels = nil view?.didReceiveUnlocks(viewModel: nil) - view?.update(model: .init(sections: [])) + view?.update(model: .init(sections: viewModelFactory.createLoadingViewModel())) } private func provideChainBalance() { @@ -386,7 +386,6 @@ extension ReferendumsPresenter: AssetSelectionDelegate { chain = chainAsset.chain clearOnAssetSwitch() - provideChainBalance() interactor.saveSelected(chainModel: chainAsset.chain) From a3fd200e05169599a320de86fae2aea5699b1b56 Mon Sep 17 00:00:00 2001 From: Gulnaz <666lynx666@mail.ru> Date: Thu, 10 Nov 2022 16:29:03 +0400 Subject: [PATCH 182/229] Show free balance for asset selection when selection was initiated from governance screen (#468) * add balance slice for asset selection * fix interactor tests * fix --- .../Modules/AssetSelection/AssetSelectionInteractor.swift | 5 ++++- .../Modules/AssetSelection/AssetSelectionViewFactory.swift | 3 +++ .../Vote/Governance/Referendums/ReferendumsWireframe.swift | 1 + .../Modules/AssetSelection/AssetSelectionTests.swift | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/novawallet/Modules/AssetSelection/AssetSelectionInteractor.swift b/novawallet/Modules/AssetSelection/AssetSelectionInteractor.swift index 65d2719fed..8bfe4326a8 100644 --- a/novawallet/Modules/AssetSelection/AssetSelectionInteractor.swift +++ b/novawallet/Modules/AssetSelection/AssetSelectionInteractor.swift @@ -11,6 +11,7 @@ final class AssetSelectionInteractor { let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let assetFilter: AssetSelectionFilter let operationQueue: OperationQueue + let balanceSlice: KeyPath private var assetBalanceSubscriptions: [AccountId: StreamableProvider] = [:] private var assetBalanceIdMapping: [String: AssetBalanceId] = [:] @@ -19,6 +20,7 @@ final class AssetSelectionInteractor { init( selectedMetaAccount: MetaAccountModel, + balanceSlice: KeyPath, repository: AnyDataProviderRepository, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, @@ -27,6 +29,7 @@ final class AssetSelectionInteractor { operationQueue: OperationQueue ) { self.selectedMetaAccount = selectedMetaAccount + self.balanceSlice = balanceSlice self.repository = repository self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory @@ -245,7 +248,7 @@ extension AssetSelectionInteractor: WalletLocalStorageSubscriber, WalletLocalSub assetId: assetBalanceId.assetId ) - accum[chainAssetId] = .success(balance.transferable) + accum[chainAssetId] = .success(balance[keyPath: balanceSlice]) case let .delete(deletedIdentifier): guard let assetBalanceId = assetBalanceIdMapping[deletedIdentifier] else { return diff --git a/novawallet/Modules/AssetSelection/AssetSelectionViewFactory.swift b/novawallet/Modules/AssetSelection/AssetSelectionViewFactory.swift index c66c4f20a4..61d2bac15d 100644 --- a/novawallet/Modules/AssetSelection/AssetSelectionViewFactory.swift +++ b/novawallet/Modules/AssetSelection/AssetSelectionViewFactory.swift @@ -1,11 +1,13 @@ import Foundation import RobinHood import SoraFoundation +import BigInt struct AssetSelectionViewFactory { static func createView( delegate: AssetSelectionDelegate, selectedChainAssetId: ChainAssetId?, + balanceSlice: KeyPath? = nil, assetFilter: @escaping AssetSelectionFilter ) -> AssetSelectionViewProtocol? { guard let currencyManager = CurrencyManager.shared else { @@ -18,6 +20,7 @@ struct AssetSelectionViewFactory { let interactor = AssetSelectionInteractor( selectedMetaAccount: SelectedWalletSettings.shared.value, + balanceSlice: balanceSlice ?? \.transferable, repository: AnyDataProviderRepository(repository), walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, priceLocalSubscriptionFactory: PriceProviderFactory.shared, diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index 10f83ba343..f7356bf089 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -19,6 +19,7 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { guard let selectionView = AssetSelectionViewFactory.createView( delegate: delegate, selectedChainAssetId: selectedChainAssetId, + balanceSlice: \.freeInPlank, assetFilter: assetFilter ) else { return diff --git a/novawalletTests/Modules/AssetSelection/AssetSelectionTests.swift b/novawalletTests/Modules/AssetSelection/AssetSelectionTests.swift index 104333b6f5..180fdc2287 100644 --- a/novawalletTests/Modules/AssetSelection/AssetSelectionTests.swift +++ b/novawalletTests/Modules/AssetSelection/AssetSelectionTests.swift @@ -42,6 +42,7 @@ class AssetSelectionTests: XCTestCase { let interactor = AssetSelectionInteractor( selectedMetaAccount: selectedAccount, + balanceSlice: \.transferable, repository: repository, walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, priceLocalSubscriptionFactory: priceProviderFactory, From 5c05ba4fb03d64a6dc899eb6de807cc9b68462f8 Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 10 Nov 2022 23:00:04 +0500 Subject: [PATCH 183/229] add full description screen --- Podfile | 2 +- Podfile.lock | 10 +- novawallet.xcodeproj/project.pbxproj | 16 +- novawallet/Common/Model/MarkdownText.swift | 10 ++ .../ReferendumDetailsPresenter.swift | 21 ++- .../ReferendumDetailsProtocols.swift | 6 +- .../ReferendumDetailsViewController.swift | 10 ++ .../ReferendumDetailsWireframe.swift | 6 +- .../View/ReferendumDetailsTitleView.swift | 34 ++--- .../ReferendumFullDescriptionPresenter.swift | 12 +- ...erendumFullDescriptionViewController.swift | 14 +- ...ReferendumFullDescriptionViewFactory.swift | 10 +- .../ReferendumFullDescriptionViewLayout.swift | 44 ++++-- .../MarkdownParsingOperationFactory.swift | 100 ++++++++++++ .../Governance/View/MarkdownView+load.swift | 60 -------- .../View/MarkdownViewContainer.swift | 144 ++++++++++++++++++ .../ReferendumMetadataViewModelFactory.swift | 15 +- 17 files changed, 382 insertions(+), 132 deletions(-) create mode 100644 novawallet/Common/Model/MarkdownText.swift create mode 100644 novawallet/Modules/Vote/Governance/View/MarkdownParsingOperationFactory.swift delete mode 100644 novawallet/Modules/Vote/Governance/View/MarkdownView+load.swift create mode 100644 novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift diff --git a/Podfile b/Podfile index 1e38447297..6328a956a5 100644 --- a/Podfile +++ b/Podfile @@ -22,7 +22,7 @@ abstract_target 'novawalletAll' do pod 'Charts' pod 'SwiftRLP', :git => 'https://github.com/ERussel/SwiftRLP.git' pod 'Starscream', :git => 'https://github.com/ERussel/Starscream.git', :tag => '4.0.5' - pod 'MarkdownView' + pod 'CDMarkdownKit', '2.3.0' target 'novawalletTests' do inherit! :search_paths diff --git a/Podfile.lock b/Podfile.lock index a6bdfa0016..2045ed2eb1 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,5 +1,6 @@ PODS: - BigInt (5.2.0) + - CDMarkdownKit (2.3.0) - Charts (4.1.0): - Charts/Core (= 4.1.0) - Charts/Core (4.1.0): @@ -39,7 +40,6 @@ PODS: - IrohaCrypto/Common - keccak.c (0.1.3) - Kingfisher (6.3.0) - - MarkdownView (1.9.1) - R.swift (5.4.0): - R.swift.Library (~> 5.3.0) - R.swift.Library (5.3.0) @@ -126,12 +126,12 @@ PODS: - xxHash-Swift (1.0.13) DEPENDENCIES: + - CDMarkdownKit (= 2.3.0) - Charts - CommonWallet/Core (from `https://github.com/ERussel/Capital-iOS.git`, tag `1.16.0`) - Cuckoo - FireMock - Kingfisher - - MarkdownView - R.swift - ReachabilitySwift - RobinHood (~> 2.6.0) @@ -151,6 +151,7 @@ DEPENDENCIES: SPEC REPOS: trunk: - BigInt + - CDMarkdownKit - Charts - CocoaLumberjack - Cuckoo @@ -158,7 +159,6 @@ SPEC REPOS: - IrohaCrypto - keccak.c - Kingfisher - - MarkdownView - R.swift - R.swift.Library - ReachabilitySwift @@ -217,6 +217,7 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: BigInt: f668a80089607f521586bbe29513d708491ef2f7 + CDMarkdownKit: 9154c4e31f105e6a83b726412787d85e56edba46 Charts: 354f86803d11d9c35de280587fef50d1af063978 CocoaLumberjack: b7e05132ff94f6ae4dfa9d5bce9141893a21d9da CommonWallet: 59fdbf5511d6fcdc38496db4baf425dd0cf29274 @@ -225,7 +226,6 @@ SPEC CHECKSUMS: IrohaCrypto: 6be75a4268cd1f5cec4231c6d3f95cb03f723fd3 keccak.c: 859583afdaccb4e4fcc0f0096064d101580313f4 Kingfisher: 6c3df386db71d82c0817a429d2c9421a77396529 - MarkdownView: 22249778219cc22901f1454e8355298dd0bda7f0 R.swift: c533450b0f7dc494e0993f5f1a1db925d84c3006 R.swift.Library: 0fc583cb55a99e28901299cc451614cad1161962 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 @@ -248,6 +248,6 @@ SPEC CHECKSUMS: TweetNacl: 3abf4d1d2082b0114e7a67410e300892448951e6 xxHash-Swift: 30bd6a7507b3b7348a277c49b1cb6346c2905ec7 -PODFILE CHECKSUM: f908a1517da883de596e198df70699d46c3496b1 +PODFILE CHECKSUM: f717aca984f7000395f683957acb94373c645eaf COCOAPODS: 1.11.3 diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index ca531e077f..4324859436 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1599,6 +1599,9 @@ 849C066F2765140B00394C82 /* AnyCancellableCleaning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849C066E2765140B00394C82 /* AnyCancellableCleaning.swift */; }; 849C0671276516F900394C82 /* BaseOperation+Cancellable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849C0670276516F900394C82 /* BaseOperation+Cancellable.swift */; }; 849D3220291C26BA00D25839 /* GovernanceDAppList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D321F291C26BA00D25839 /* GovernanceDAppList.swift */; }; + 849D3223291CC43D00D25839 /* MarkdownText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D3222291CC43D00D25839 /* MarkdownText.swift */; }; + 849D3225291CC4A500D25839 /* MarkdownParsingOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D3224291CC4A500D25839 /* MarkdownParsingOperationFactory.swift */; }; + 849D3227291CE25E00D25839 /* MarkdownViewContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D3226291CE25E00D25839 /* MarkdownViewContainer.swift */; }; 849D755B2756910A007726C3 /* RoundedView+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D755A2756910A007726C3 /* RoundedView+Style.swift */; }; 849D755D27577602007726C3 /* AccountExportPasswordViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D755C27577602007726C3 /* AccountExportPasswordViewLayout.swift */; }; 849DEBD425ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849DEBD325ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift */; }; @@ -2291,7 +2294,6 @@ 880855FC28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880855FB28D0C3DF004255E7 /* CrowdloansLocalStorageSubscriber.swift */; }; 88107D5F290133F8001AB0B0 /* RoundedView+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */; }; 88107D6129015FAB001AB0B0 /* TrackTagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */; }; - 882232E92919226000CBA7B3 /* MarkdownView+load.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882232E82919225E00CBA7B3 /* MarkdownView+load.swift */; }; 8824D4222902D92F0022D778 /* ReferendumFullDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */; }; 8824D424290324260022D778 /* PrettyPrintedJSONOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D423290324260022D778 /* PrettyPrintedJSONOperationFactory.swift */; }; 8824D42629032B410022D778 /* BlurredView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8824D42529032B410022D778 /* BlurredView.swift */; }; @@ -4592,6 +4594,9 @@ 849C066E2765140B00394C82 /* AnyCancellableCleaning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyCancellableCleaning.swift; sourceTree = ""; }; 849C0670276516F900394C82 /* BaseOperation+Cancellable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseOperation+Cancellable.swift"; sourceTree = ""; }; 849D321F291C26BA00D25839 /* GovernanceDAppList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceDAppList.swift; sourceTree = ""; }; + 849D3222291CC43D00D25839 /* MarkdownText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownText.swift; sourceTree = ""; }; + 849D3224291CC4A500D25839 /* MarkdownParsingOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownParsingOperationFactory.swift; sourceTree = ""; }; + 849D3226291CE25E00D25839 /* MarkdownViewContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownViewContainer.swift; sourceTree = ""; }; 849D755A2756910A007726C3 /* RoundedView+Style.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RoundedView+Style.swift"; sourceTree = ""; }; 849D755C27577602007726C3 /* AccountExportPasswordViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountExportPasswordViewLayout.swift; sourceTree = ""; }; 849DEBD325ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmViewModel.swift; sourceTree = ""; }; @@ -5292,7 +5297,6 @@ 88107D5E290133F8001AB0B0 /* RoundedView+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RoundedView+Styles.swift"; sourceTree = ""; }; 88107D6029015FAB001AB0B0 /* TrackTagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackTagsView.swift; sourceTree = ""; }; 8821119C96944A0E3526E93A /* StakingRedeemViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRedeemViewFactory.swift; sourceTree = ""; }; - 882232E82919225E00CBA7B3 /* MarkdownView+load.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MarkdownView+load.swift"; sourceTree = ""; }; 8824D4212902D92F0022D778 /* ReferendumFullDetailsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsInteractor.swift; sourceTree = ""; }; 8824D423290324260022D778 /* PrettyPrintedJSONOperationFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrettyPrintedJSONOperationFactory.swift; sourceTree = ""; }; 8824D42529032B410022D778 /* BlurredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurredView.swift; sourceTree = ""; }; @@ -9479,6 +9483,7 @@ 887AFC8628BC95F0002A0422 /* MetaAccountChainResponse.swift */, 8831F0FF28C65B95009F7682 /* AssetLock.swift */, 2AC7BC832731A214001D99B0 /* AssetLocks+Sort.swift */, + 849D3222291CC43D00D25839 /* MarkdownText.swift */, ); path = Model; sourceTree = ""; @@ -12513,7 +12518,6 @@ 880059D628EEA55500E87B9B /* View */ = { isa = PBXGroup; children = ( - 882232E82919225E00CBA7B3 /* MarkdownView+load.swift */, 880059DD28EF093400E87B9B /* Slider */, 880059E028EF0A5C00E87B9B /* VotingProgressView.swift */, 880059E228EF128000E87B9B /* ReferendumInfoView.swift */, @@ -12522,6 +12526,8 @@ 889D889628F022AA00C4320F /* UILabel+Style.swift */, 88F34FDC28FFE6E400712BDE /* MultiValueView+Model.swift */, 84033056290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift */, + 849D3226291CE25E00D25839 /* MarkdownViewContainer.swift */, + 849D3224291CC4A500D25839 /* MarkdownParsingOperationFactory.swift */, ); path = View; sourceTree = ""; @@ -14811,6 +14817,7 @@ 847ABE332853333A00851218 /* StakingSharedState+Duration.swift in Sources */, 8424A8C7262EC0E50091BFB1 /* PayoutInfo.swift in Sources */, 843910C7253F56EA00E3C217 /* BaseOperation+Result.swift in Sources */, + 849D3225291CC4A500D25839 /* MarkdownParsingOperationFactory.swift in Sources */, 84D6D7FE27A7F4CD0094FC33 /* AssetListChainView.swift in Sources */, 842D1E8424D197C900C30A7A /* KeyboardAdoptable.swift in Sources */, 849DEBD425ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift in Sources */, @@ -15288,6 +15295,7 @@ 8444D1BE2671465A00AF6D8C /* CrowdloanBonusServiceError.swift in Sources */, 8448F7A22882ABF50080CEA9 /* CustomSearchView.swift in Sources */, 84D2F1AF2774CEF00040C680 /* DAppURLBarView.swift in Sources */, + 849D3223291CC43D00D25839 /* MarkdownText.swift in Sources */, 84FFE45B2862076F002432BB /* XcmUnweightedTransferRequest.swift in Sources */, 84D1110C26B922D50016D962 /* ConnectionPool.swift in Sources */, 8490152E24ABD0F5008F705E /* Logger+Wallet.swift in Sources */, @@ -15408,6 +15416,7 @@ F4223F102732D445003D8E4E /* AcalaStatementData.swift in Sources */, 847DD8DC26034B99003DE053 /* LocalizableViewProtocol.swift in Sources */, F4CE0F9527343E630094CD8A /* AcalaContributionConfirmPresenter.swift in Sources */, + 849D3227291CE25E00D25839 /* MarkdownViewContainer.swift in Sources */, 847297CF260B4035009B86D0 /* ChangeTargetConfirmInteractor.swift in Sources */, 8428768724AE046300D91AD8 /* LanguageSelectionViewFactory.swift in Sources */, 84FB9E26285C6C5000B42FC0 /* XcmVersionedMultiasset.swift in Sources */, @@ -15621,7 +15630,6 @@ AE6F7FE42685E812002BBC3E /* ValidatorListFilterViewFactory.swift in Sources */, 842876AA24AE049B00D91AD8 /* SelectionTitleTableViewCell.swift in Sources */, 84CA68DD26BEA60A003B9453 /* ConnectionFactory.swift in Sources */, - 882232E92919226000CBA7B3 /* MarkdownView+load.swift in Sources */, F40966B626B297D6008CD244 /* AnalyticsRewardsPresenter.swift in Sources */, 84A58FD428A05820003F6ABF /* HardwareSigningError.swift in Sources */, F4B39C53273270A300BB6E10 /* AcalaContributionSetupPresenter.swift in Sources */, diff --git a/novawallet/Common/Model/MarkdownText.swift b/novawallet/Common/Model/MarkdownText.swift new file mode 100644 index 0000000000..f4632aa5db --- /dev/null +++ b/novawallet/Common/Model/MarkdownText.swift @@ -0,0 +1,10 @@ +import UIKit + +struct MarkdownText { + static let readMoreThreshold = 180 + + let originalString: String + let attributedString: NSAttributedString + let preferredSize: CGSize + let isFull: Bool +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 146cd99db0..28e0d3492b 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -3,8 +3,6 @@ import SoraFoundation import SubstrateSdk final class ReferendumDetailsPresenter { - static let readMoreThreshold = 180 - weak var view: ReferendumDetailsViewProtocol? let wireframe: ReferendumDetailsWireframeProtocol let interactor: ReferendumDetailsInteractorInputProtocol @@ -107,7 +105,6 @@ final class ReferendumDetailsPresenter { let detailsViewModel = referendumMetadataViewModelFactory.createDetailsViewModel( for: referendum, metadata: referendumMetadata, - readMoreThreshold: Self.readMoreThreshold, locale: selectedLocale ) @@ -373,11 +370,13 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { } func readFullDescription() { - guard let metadata = referendumMetadata else { - return - } + let viewModel = referendumMetadataViewModelFactory.createDetailsViewModel( + for: referendum, + metadata: referendumMetadata, + locale: selectedLocale + ) - wireframe.showFullDescription(from: view, referendumMetadata: metadata) + wireframe.showFullDescription(from: view, title: viewModel.title, description: viewModel.description) } func openFullDetails() { @@ -392,6 +391,14 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { identities: identities ?? [:] ) } + + func openURL(_ url: URL) { + guard let view = view else { + return + } + + wireframe.showWeb(url: url, from: view, style: .automatic) + } } extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 29b98d4453..c29470e372 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -21,6 +21,7 @@ protocol ReferendumDetailsPresenterProtocol: AnyObject { func opeDApp(at index: Int) func openFullDetails() func vote() + func openURL(_ url: URL) } protocol ReferendumDetailsInteractorInputProtocol: AnyObject { @@ -46,7 +47,7 @@ protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { } protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, - AddressOptionsPresentable { + AddressOptionsPresentable, WebPresentable { func showFullDetails( from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal, @@ -64,7 +65,8 @@ protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, func showFullDescription( from view: ReferendumDetailsViewProtocol?, - referendumMetadata: ReferendumMetadataLocal + title: String, + description: String ) func showDApp(from view: ReferendumDetailsViewProtocol?, url: URL) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift index 14677df7cb..16d72d1456 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewController.swift @@ -73,6 +73,8 @@ final class ReferendumDetailsViewController: UIViewController, ViewHolder { action: #selector(actionFullDetails), for: .touchUpInside ) + + rootView.titleView.descriptionView.delegate = self } @objc private func actionVote() { @@ -128,6 +130,8 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { func didReceive(titleModel: ReferendumDetailsTitleView.Model) { rootView.titleView.bind(viewModel: titleModel, locale: localizationManager.selectedLocale) + + rootView.setNeedsLayout() } func didReceive(yourVoteModel: YourVoteRow.Model?) { @@ -156,3 +160,9 @@ extension ReferendumDetailsViewController: ReferendumDetailsViewProtocol { rootView.timelineView.bind(activeTimeViewModel: activeTimeViewModel) } } + +extension ReferendumDetailsViewController: MarkdownViewContainerDelegate { + func markdownView(_: MarkdownViewContainer, asksHandle url: URL) { + presenter.openURL(url) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index b23fdd2ef3..11fb4b8175 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -63,11 +63,13 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { func showFullDescription( from view: ReferendumDetailsViewProtocol?, - referendumMetadata: ReferendumMetadataLocal + title: String, + description: String ) { guard let fullDescriptionView = ReferendumFullDescriptionViewFactory.createView( - for: referendumMetadata + for: title, + description: description ) else { return } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift index 3293fd7777..7f5bd5b48c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/View/ReferendumDetailsTitleView.swift @@ -1,6 +1,6 @@ import UIKit import SoraUI -import MarkdownView +import CDMarkdownKit final class ReferendumDetailsTitleView: UIView { var accountIconSize: CGSize { @@ -39,9 +39,10 @@ final class ReferendumDetailsTitleView: UIView { $0.numberOfLines = 0 } - let descriptionView: MarkdownView = .create { - $0.isScrollEnabled = false - } + let descriptionView = MarkdownViewContainer( + preferredWidth: UIScreen.main.bounds.width - 2 * UIConstants.horizontalInset, + maxTextLength: MarkdownText.readMoreThreshold + ) let moreButton: RoundedButton = .create { button in button.applyIconStyle() @@ -83,16 +84,6 @@ final class ReferendumDetailsTitleView: UIView { content.snp.makeConstraints { $0.edges.equalToSuperview() } - descriptionView.onRendered = { [weak self] contentHeight in - self?.updateMarkdownView(height: contentHeight) - } - } - - private func updateMarkdownView(height: CGFloat) { - descriptionView.snp.updateConstraints { - $0.height.equalTo(height) - $0.leading.trailing.equalToSuperview() - } } } @@ -105,7 +96,6 @@ extension ReferendumDetailsTitleView { struct Details { let title: String let description: String - let shouldReadMore: Bool } func bind(viewModel: Model, locale: Locale) { @@ -140,17 +130,17 @@ extension ReferendumDetailsTitleView { titleLabel.isHidden = false titleLabel.text = details.title - if !details.description.isEmpty { - descriptionView.isHidden = false - descriptionView.loadLimitedText( - markdownText: details.description, - maxLinesCount: 4 - ) + moreButton.isHidden = true + + descriptionView.isHidden = false + descriptionView.load(from: details.description) { [weak self] (model: MarkdownText?) in + if let shouldReadMore = model?.isFull { + self?.moreButton.isHidden = shouldReadMore + } } moreButton.imageWithTitleView?.title = R.string.localizable.commonReadMore( preferredLanguages: locale.rLanguages ) - moreButton.isHidden = !details.shouldReadMore } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift index f37f81df68..253b3fd4bf 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionPresenter.swift @@ -5,22 +5,32 @@ final class ReferendumFullDescriptionPresenter { let wireframe: ReferendumFullDescriptionWireframeProtocol let interactor: ReferendumFullDescriptionInteractorInputProtocol + let title: String + let description: String + init( + title: String, + description: String, interactor: ReferendumFullDescriptionInteractorInputProtocol, wireframe: ReferendumFullDescriptionWireframeProtocol ) { + self.title = title + self.description = description self.interactor = interactor self.wireframe = wireframe } } extension ReferendumFullDescriptionPresenter: ReferendumFullDescriptionPresenterProtocol { - func setup() {} + func setup() { + view?.didReceive(title: title, description: description) + } func open(url: URL) { guard let view = view else { return } + wireframe.showWeb( url: url, from: view, diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift index a0c302171b..b965316cd7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewController.swift @@ -27,13 +27,7 @@ final class ReferendumFullDescriptionViewController: UIViewController, ViewHolde } private func setupHandlers() { - rootView.markdownView.onTouchLink = { [weak self] request in - guard let url = request.url, url.scheme == "https" else { - return false - } - self?.presenter.open(url: url) - return false - } + rootView.markdownView.delegate = self } } @@ -43,3 +37,9 @@ extension ReferendumFullDescriptionViewController: ReferendumFullDescriptionView rootView.set(markdownText: description) } } + +extension ReferendumFullDescriptionViewController: MarkdownViewContainerDelegate { + func markdownView(_: MarkdownViewContainer, asksHandle url: URL) { + presenter.open(url: url) + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift index 296ac8a592..5f770e2b3d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewFactory.swift @@ -2,12 +2,18 @@ import Foundation struct ReferendumFullDescriptionViewFactory { static func createView( - for _: ReferendumMetadataLocal + for title: String, + description: String ) -> ReferendumFullDescriptionViewProtocol? { let interactor = ReferendumFullDescriptionInteractor() let wireframe = ReferendumFullDescriptionWireframe() - let presenter = ReferendumFullDescriptionPresenter(interactor: interactor, wireframe: wireframe) + let presenter = ReferendumFullDescriptionPresenter( + title: title, + description: description, + interactor: interactor, + wireframe: wireframe + ) let view = ReferendumFullDescriptionViewController(presenter: presenter) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift index fd2c24f0ac..5b5811c95c 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDescription/ReferendumFullDescriptionViewLayout.swift @@ -1,5 +1,5 @@ import UIKit -import MarkdownView +import CDMarkdownKit final class ReferendumFullDescriptionViewLayout: UIView { let containerView: ScrollableContainerView = { @@ -16,18 +16,20 @@ final class ReferendumFullDescriptionViewLayout: UIView { $0.numberOfLines = 0 } - let markdownView = MarkdownView() + let markdownView = MarkdownViewContainer( + preferredWidth: UIScreen.main.bounds.width - 2 * UIConstants.horizontalInset + ) + + let activityIndicator: UIActivityIndicatorView = .create { + $0.hidesWhenStopped = true + } override init(frame: CGRect) { super.init(frame: frame) - addSubview(containerView) - containerView.snp.makeConstraints { - $0.edges.equalToSuperview() - } - containerView.stackView.addArrangedSubview(titleLabel) - containerView.stackView.addArrangedSubview(markdownView) - containerView.stackView.setCustomSpacing(16, after: titleLabel) + backgroundColor = R.color.colorBlack() + + setupLayout() } @available(*, unavailable) @@ -36,10 +38,32 @@ final class ReferendumFullDescriptionViewLayout: UIView { } func set(markdownText: String) { - markdownView.loadFull(markdownText: markdownText) + activityIndicator.startAnimating() + + markdownView.load(from: markdownText) { [weak self] model in + if model != nil { + self?.activityIndicator.stopAnimating() + } + } } func set(title: String) { titleLabel.text = title } + + private func setupLayout() { + addSubview(containerView) + containerView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + + containerView.stackView.addArrangedSubview(titleLabel) + containerView.stackView.addArrangedSubview(markdownView) + containerView.stackView.setCustomSpacing(16, after: titleLabel) + + addSubview(activityIndicator) + activityIndicator.snp.makeConstraints { make in + make.center.equalToSuperview() + } + } } diff --git a/novawallet/Modules/Vote/Governance/View/MarkdownParsingOperationFactory.swift b/novawallet/Modules/Vote/Governance/View/MarkdownParsingOperationFactory.swift new file mode 100644 index 0000000000..1091980fe6 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/MarkdownParsingOperationFactory.swift @@ -0,0 +1,100 @@ +import Foundation +import RobinHood +import CDMarkdownKit +import UIKit + +protocol MarkdownParsingOperationFactoryProtocol { + func createParseOperation(for string: String, preferredWidth: CGFloat) -> BaseOperation +} + +final class MarkdownParsingOperationFactory: MarkdownParsingOperationFactoryProtocol { + let maxSize: Int? + + init(maxSize: Int?) { + self.maxSize = maxSize + } + + private func createMarkdownParser(for preferredWidth: CGFloat) -> CDMarkdownParser { + let textParagraphStyle = NSMutableParagraphStyle() + textParagraphStyle.paragraphSpacing = 8 + textParagraphStyle.paragraphSpacingBefore = 8 + + let parser = CDMarkdownParser( + font: CDFont.systemFont(ofSize: 15), + fontColor: R.color.colorTransparentText()!, + paragraphStyle: textParagraphStyle + ) + + parser.bold.color = R.color.colorTransparentText()! + parser.bold.backgroundColor = nil + parser.header.color = R.color.colorWhite()! + parser.header.backgroundColor = nil + parser.list.color = R.color.colorTransparentText()! + parser.list.backgroundColor = nil + parser.quote.color = R.color.colorTransparentText() + parser.quote.backgroundColor = nil + parser.link.color = R.color.colorNovaBlue()! + parser.link.backgroundColor = nil + parser.automaticLink.color = R.color.colorNovaBlue()! + parser.automaticLink.backgroundColor = nil + parser.italic.color = R.color.colorTransparentText()! + parser.italic.backgroundColor = nil + let codeParagraphStyle = NSMutableParagraphStyle() + parser.code.font = UIFont.systemFont(ofSize: 15) + parser.code.color = R.color.colorWhite()! + parser.code.backgroundColor = UIColor(white: 20.0 / 256.0, alpha: 1.0) + parser.code.paragraphStyle = codeParagraphStyle + parser.syntax.font = UIFont.systemFont(ofSize: 15) + parser.syntax.color = R.color.colorWhite()! + parser.syntax.backgroundColor = UIColor(white: 20.0 / 256.0, alpha: 1.0) + + // library uses only width internally and adjusts the height of the image + parser.image.size = CGSize(width: preferredWidth, height: 0) + + return parser + } + + private func createOperation( + for string: String, + preferredWidth: CGFloat, + maxSize: Int? + ) -> BaseOperation { + ClosureOperation { + let preprocessed: String + let isFull: Bool + + let parser: CDMarkdownParser + + if let maxSize = maxSize { + isFull = string.count <= maxSize + preprocessed = string.convertToReadMore(after: maxSize) + parser = self.createMarkdownParser(for: preferredWidth) + } else { + isFull = true + preprocessed = string + parser = self.createMarkdownParser(for: preferredWidth) + } + + let attributedString = parser.parse(preprocessed) + + let preferredHeight = attributedString.boundingRect( + with: CGSize(width: preferredWidth, height: 0), + options: .usesLineFragmentOrigin, + context: nil + ).height + + let preferredSize = CGSize(width: preferredWidth, height: preferredHeight) + + return .init( + originalString: string, + attributedString: attributedString, + preferredSize: preferredSize, + isFull: isFull + ) + } + } + + func createParseOperation(for string: String, preferredWidth: CGFloat) -> BaseOperation { + createOperation(for: string, preferredWidth: preferredWidth, maxSize: maxSize) + } +} diff --git a/novawallet/Modules/Vote/Governance/View/MarkdownView+load.swift b/novawallet/Modules/Vote/Governance/View/MarkdownView+load.swift deleted file mode 100644 index eff9d91a83..0000000000 --- a/novawallet/Modules/Vote/Governance/View/MarkdownView+load.swift +++ /dev/null @@ -1,60 +0,0 @@ -import MarkdownView -import CoreGraphics - -extension MarkdownView { - func loadFull(markdownText: String) { - load( - markdown: markdownText, - css: css(coloredLink: R.color.colorNovaBlue()), - plugins: plugins() - ) - } - - func loadLimitedText( - markdownText: String, - maxLinesCount: Int - ) { - let css = [ - css(coloredLink: R.color.colorNovaBlue()), - css(maxLinesCount: maxLinesCount) - ].compactMap { $0 }.joined(separator: "\n") - - return load( - markdown: markdownText, - enableImage: false, - css: css, - plugins: plugins() - ) - } - - private func plugins() -> [String]? { - [ - URL(string: "https://cdnjs.cloudflare.com/ajax/libs/markdown-it-footnote/3.0.3/markdown-it-footnote.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-sub@1.0.0/index.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-sup@1.0.0/index.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-ins@3.0.1/dist/markdown-it-ins.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-mark@3.0.1/dist/markdown-it-mark.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-container@3.0.0/dist/markdown-it-container.min.js"), - URL(string: "https://cdn.jsdelivr.net/npm/markdown-it-deflist@2.1.0/dist/markdown-it-deflist.min.js") - ].compactMap { $0 } - .compactMap { try? String(contentsOf: $0, encoding: .utf8) } - } - - private func css(coloredLink color: UIColor?) -> String? { - guard let color = color else { - return nil - } - return "a { color: \(color); }" - } - - private func css(maxLinesCount: Int) -> String { - """ - p { - -webkit-line-clamp: \(maxLinesCount); - display: -webkit-box; - -webkit-box-orient: vertical; - overflow: hidden; - } - """ - } -} diff --git a/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift b/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift new file mode 100644 index 0000000000..eeb1d3b688 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift @@ -0,0 +1,144 @@ +import UIKit +import CDMarkdownKit +import RobinHood + +protocol MarkdownViewContainerDelegate: AnyObject { + func markdownView(_ view: MarkdownViewContainer, asksHandle url: URL) +} + +final class MarkdownViewContainer: UIView, AnyCancellableCleaning { + private var textView: CDMarkdownTextView? + + private var model: MarkdownText? + let preferredWidth: CGFloat + + override var intrinsicContentSize: CGSize { + CGSize(width: preferredWidth, height: model?.preferredSize.height ?? 0) + } + + let operationQueue: OperationQueue + + private let operationFactory: MarkdownParsingOperationFactoryProtocol + + private var operation: CancellableCall? + + weak var delegate: MarkdownViewContainerDelegate? + + init( + preferredWidth: CGFloat, + maxTextLength: Int? = nil, + operationQueue: OperationQueue = OperationQueue() + ) { + self.preferredWidth = preferredWidth + operationFactory = MarkdownParsingOperationFactory(maxSize: maxTextLength) + self.operationQueue = operationQueue + + super.init(frame: .zero) + } + + deinit { + clear(cancellable: &operation) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func clearTextView() { + textView?.removeFromSuperview() + textView = nil + } + + func setupTextView(for size: CGSize, text: NSAttributedString) { + clearTextView() + + let textContainer = NSTextContainer(size: size) + let layoutManager = CDMarkdownLayoutManager() + layoutManager.addTextContainer(textContainer) + + let textView = CDMarkdownTextView( + frame: .init(origin: .zero, size: size), + textContainer: textContainer, + layoutManager: layoutManager + ) + + textView.delegate = self + + textView.isEditable = false + textView.isScrollEnabled = false + textView.isSelectable = true + textView.textContainerInset = .zero + textView.textContainer.lineFragmentPadding = 0 + textView.roundAllCorners = true + + textView.backgroundColor = .clear + + addSubview(textView) + + textView.snp.makeConstraints { make in + make.leading.trailing.top.bottom.equalToSuperview() + } + + textView.attributedText = text + + self.textView = textView + } + + private func bind(model: MarkdownText) { + self.model = model + + setupTextView(for: model.preferredSize, text: model.attributedString) + + invalidateIntrinsicContentSize() + } +} + +extension MarkdownViewContainer { + func load(from string: String, completion: ((MarkdownText?) -> Void)?) { + guard model?.originalString != string else { + completion?(model) + return + } + + model = nil + + clear(cancellable: &operation) + clearTextView() + + let parsingOperation = operationFactory.createParseOperation(for: string, preferredWidth: preferredWidth) + + parsingOperation.completionBlock = { [weak self] in + DispatchQueue.main.async { + guard self?.operation === parsingOperation else { + completion?(nil) + return + } + + do { + let model = try parsingOperation.extractNoCancellableResultData() + self?.bind(model: model) + completion?(model) + } catch { + completion?(nil) + } + } + } + + operation = parsingOperation + + operationQueue.addOperation(parsingOperation) + } +} + +extension MarkdownViewContainer: UITextViewDelegate { + func textView( + _: UITextView, + shouldInteractWith URL: URL, + in _: NSRange, + interaction _: UITextItemInteraction + ) -> Bool { + delegate?.markdownView(self, asksHandle: URL) + return false + } +} diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift index 745d56f30e..04c74ad394 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumMetadataViewModelFactory.swift @@ -19,19 +19,12 @@ extension ReferendumMetadataViewModelFactoryProtocol { func createDetailsViewModel( for referendum: ReferendumLocal, metadata: ReferendumMetadataLocal?, - readMoreThreshold: Int?, locale: Locale ) -> ReferendumDetailsTitleView.Details { let title = createTitle(for: referendum, metadata: metadata, locale: locale) let description = createDescription(for: referendum, metadata: metadata, locale: locale) - if let readMoreThreshold = readMoreThreshold, description.count > readMoreThreshold { - let readMoreDescription = description.convertToReadMore(after: readMoreThreshold) - - return .init(title: title, description: readMoreDescription, shouldReadMore: true) - } else { - return .init(title: title, description: description, shouldReadMore: false) - } + return .init(title: title, description: description) } } @@ -57,7 +50,11 @@ extension ReferendumMetadataViewModelFactory: ReferendumMetadataViewModelFactory } } - func createDescription(for _: ReferendumLocal, metadata: ReferendumMetadataLocal?, locale: Locale) -> String { + func createDescription( + for _: ReferendumLocal, + metadata: ReferendumMetadataLocal?, + locale: Locale + ) -> String { if let description = metadata?.content, !description.isEmpty { return description } else { From d13d6c2d6e199b3cd0b3701ba30657751c503fbe Mon Sep 17 00:00:00 2001 From: ERussel Date: Thu, 10 Nov 2022 23:49:07 +0500 Subject: [PATCH 184/229] disable images for details --- Podfile | 2 +- Podfile.lock | 11 ++++++++--- .../View/MarkdownParsingOperationFactory.swift | 9 +++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Podfile b/Podfile index 6328a956a5..cea58c89cb 100644 --- a/Podfile +++ b/Podfile @@ -22,7 +22,7 @@ abstract_target 'novawalletAll' do pod 'Charts' pod 'SwiftRLP', :git => 'https://github.com/ERussel/SwiftRLP.git' pod 'Starscream', :git => 'https://github.com/ERussel/Starscream.git', :tag => '4.0.5' - pod 'CDMarkdownKit', '2.3.0' + pod 'CDMarkdownKit', :git => 'https://github.com/nova-wallet/CDMarkdownKit.git', :commit => '2983924e34461646b6bd770a16ab6f6603fc4b24' target 'novawalletTests' do inherit! :search_paths diff --git a/Podfile.lock b/Podfile.lock index 2045ed2eb1..5bfa39913c 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -126,7 +126,7 @@ PODS: - xxHash-Swift (1.0.13) DEPENDENCIES: - - CDMarkdownKit (= 2.3.0) + - CDMarkdownKit (from `https://github.com/nova-wallet/CDMarkdownKit.git`, commit `2983924e34461646b6bd770a16ab6f6603fc4b24`) - Charts - CommonWallet/Core (from `https://github.com/ERussel/Capital-iOS.git`, tag `1.16.0`) - Cuckoo @@ -151,7 +151,6 @@ DEPENDENCIES: SPEC REPOS: trunk: - BigInt - - CDMarkdownKit - Charts - CocoaLumberjack - Cuckoo @@ -177,6 +176,9 @@ SPEC REPOS: - xxHash-Swift EXTERNAL SOURCES: + CDMarkdownKit: + :commit: 2983924e34461646b6bd770a16ab6f6603fc4b24 + :git: https://github.com/nova-wallet/CDMarkdownKit.git CommonWallet: :git: https://github.com/ERussel/Capital-iOS.git :tag: 1.16.0 @@ -196,6 +198,9 @@ EXTERNAL SOURCES: :git: https://github.com/ERussel/SwiftRLP.git CHECKOUT OPTIONS: + CDMarkdownKit: + :commit: 2983924e34461646b6bd770a16ab6f6603fc4b24 + :git: https://github.com/nova-wallet/CDMarkdownKit.git CommonWallet: :git: https://github.com/ERussel/Capital-iOS.git :tag: 1.16.0 @@ -248,6 +253,6 @@ SPEC CHECKSUMS: TweetNacl: 3abf4d1d2082b0114e7a67410e300892448951e6 xxHash-Swift: 30bd6a7507b3b7348a277c49b1cb6346c2905ec7 -PODFILE CHECKSUM: f717aca984f7000395f683957acb94373c645eaf +PODFILE CHECKSUM: ebaedd559bf22ed6a7f0f6ad82c2fb6f5342e172 COCOAPODS: 1.11.3 diff --git a/novawallet/Modules/Vote/Governance/View/MarkdownParsingOperationFactory.swift b/novawallet/Modules/Vote/Governance/View/MarkdownParsingOperationFactory.swift index 1091980fe6..80c4b2d476 100644 --- a/novawallet/Modules/Vote/Governance/View/MarkdownParsingOperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/View/MarkdownParsingOperationFactory.swift @@ -14,7 +14,7 @@ final class MarkdownParsingOperationFactory: MarkdownParsingOperationFactoryProt self.maxSize = maxSize } - private func createMarkdownParser(for preferredWidth: CGFloat) -> CDMarkdownParser { + private func createMarkdownParser(for preferredWidth: CGFloat, imageDetectionEnabled: Bool) -> CDMarkdownParser { let textParagraphStyle = NSMutableParagraphStyle() textParagraphStyle.paragraphSpacing = 8 textParagraphStyle.paragraphSpacingBefore = 8 @@ -22,7 +22,8 @@ final class MarkdownParsingOperationFactory: MarkdownParsingOperationFactoryProt let parser = CDMarkdownParser( font: CDFont.systemFont(ofSize: 15), fontColor: R.color.colorTransparentText()!, - paragraphStyle: textParagraphStyle + paragraphStyle: textParagraphStyle, + imageDetectionEnabled: imageDetectionEnabled ) parser.bold.color = R.color.colorTransparentText()! @@ -68,11 +69,11 @@ final class MarkdownParsingOperationFactory: MarkdownParsingOperationFactoryProt if let maxSize = maxSize { isFull = string.count <= maxSize preprocessed = string.convertToReadMore(after: maxSize) - parser = self.createMarkdownParser(for: preferredWidth) + parser = self.createMarkdownParser(for: preferredWidth, imageDetectionEnabled: false) } else { isFull = true preprocessed = string - parser = self.createMarkdownParser(for: preferredWidth) + parser = self.createMarkdownParser(for: preferredWidth, imageDetectionEnabled: true) } let attributedString = parser.parse(preprocessed) From a4167bfa7f706e35605b046a0bb005208abcda07 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 10:28:57 +0500 Subject: [PATCH 185/229] handle no account for governance --- .../ReferendumDetailsInteractor.swift | 48 ++++++++++++++++--- .../ReferendumDetailsPresenter.swift | 41 +++++++++++++++- .../ReferendumDetailsProtocols.swift | 5 +- .../ReferendumDetailsViewFactory.swift | 8 ++-- .../ReferendumDetailsWireframe.swift | 8 ++++ .../Referendums/ReferendumsInteractor.swift | 2 + .../Modules/Vote/Parent/VotePresenter.swift | 6 ++- 7 files changed, 104 insertions(+), 14 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 72173a6643..6324af0731 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -8,7 +8,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { private(set) var referendum: ReferendumLocal private(set) var actionDetails: ReferendumActionLocal? - let selectedAccount: ChainAccountResponse + let walletSettings: SelectedWalletSettings let chain: ChainModel let actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol let connection: JSONRPCEngine @@ -20,6 +20,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { let referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol let dAppsProvider: AnySingleValueProvider + let eventCenter: EventCenterProtocol let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? @@ -33,7 +34,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { init( referendum: ReferendumLocal, - selectedAccount: ChainAccountResponse, + walletSettings: SelectedWalletSettings, chain: ChainModel, actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol, connection: JSONRPCEngine, @@ -45,11 +46,12 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol, referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, dAppsProvider: AnySingleValueProvider, + eventCenter: EventCenterProtocol, currencyManager: CurrencyManagerProtocol, operationQueue: OperationQueue ) { self.referendum = referendum - self.selectedAccount = selectedAccount + self.walletSettings = walletSettings self.chain = chain self.actionDetailsOperationFactory = actionDetailsOperationFactory self.connection = connection @@ -61,6 +63,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { self.govMetadataLocalSubscriptionFactory = govMetadataLocalSubscriptionFactory self.referendumsSubscriptionFactory = referendumsSubscriptionFactory self.dAppsProvider = dAppsProvider + self.eventCenter = eventCenter self.operationQueue = operationQueue self.currencyManager = currencyManager } @@ -72,7 +75,18 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { clear(cancellable: &dAppsCancellable) referendumsSubscriptionFactory.unsubscribeFromReferendum(self, referendumIndex: referendum.index) - referendumsSubscriptionFactory.unsubscribeFromAccountVotes(self, accountId: selectedAccount.accountId) + + if let accountId = selectedAccountId() { + referendumsSubscriptionFactory.unsubscribeFromAccountVotes(self, accountId: accountId) + } + } + + private func selectedAccountId() -> AccountId? { + walletSettings.value?.fetch(for: chain.accountRequest())?.accountId + } + + private func provideSelectedWallet() { + presenter?.didReceiveWallet(walletSettings.value) } private func subscribeReferendum() { @@ -97,11 +111,16 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { } private func subscribeAccountVotes() { - referendumsSubscriptionFactory.unsubscribeFromAccountVotes(self, accountId: selectedAccount.accountId) + guard let accountId = selectedAccountId() else { + presenter?.didReceiveAccountVotes(nil) + return + } + + referendumsSubscriptionFactory.unsubscribeFromAccountVotes(self, accountId: accountId) referendumsSubscriptionFactory.subscribeToAccountVotes( self, - accountId: selectedAccount.accountId + accountId: accountId ) { [weak self] result in switch result { case let .success(votesResult): @@ -253,6 +272,10 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } + private func makeAccountBasedSubscriptions() { + subscribeAccountVotes() + } + private func makeSubscriptions() { if let priceId = chain.utilityAsset()?.priceId { priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) @@ -261,7 +284,8 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { blockNumberSubscription = subscribeToBlockNumber(for: chain.chainId) subscribeReferendum() - subscribeAccountVotes() + + makeAccountBasedSubscriptions() metadataProvider = subscribeGovernanceMetadata(for: chain, referendumId: referendum.index) @@ -275,9 +299,12 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol { func setup() { + provideSelectedWallet() makeSubscriptions() updateActionDetails() subscribeDApps() + + eventCenter.add(observer: self, dispatchIn: .main) } func remakeDAppsSubscription() { @@ -358,3 +385,10 @@ extension ReferendumDetailsInteractor: SelectedCurrencyDepending { } } } + +extension ReferendumDetailsInteractor: EventVisitorProtocol { + func processSelectedAccountChanged(event _: SelectedAccountChanged) { + provideSelectedWallet() + makeAccountBasedSubscriptions() + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 28e0d3492b..9c75b9fd1e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -14,10 +14,12 @@ final class ReferendumDetailsPresenter { let referendumMetadataViewModelFactory: ReferendumMetadataViewModelFactoryProtocol let displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol + let accountManagementFilter: AccountManagementFilterProtocol let chain: ChainModel let logger: LoggerProtocol + private var wallet: MetaAccountModel? private var referendum: ReferendumLocal private var actionDetails: ReferendumActionLocal? private var accountVotes: ReferendumAccountVoteLocal? @@ -37,6 +39,7 @@ final class ReferendumDetailsPresenter { init( referendum: ReferendumLocal, chain: ChainModel, + accountManagementFilter: AccountManagementFilterProtocol, accountVotes: ReferendumAccountVoteLocal?, metadata: ReferendumMetadataLocal?, interactor: ReferendumDetailsInteractorInputProtocol, @@ -54,6 +57,7 @@ final class ReferendumDetailsPresenter { ) { self.interactor = interactor self.wireframe = wireframe + self.accountManagementFilter = accountManagementFilter self.referendumViewModelFactory = referendumViewModelFactory self.referendumStringsFactory = referendumStringsFactory self.balanceViewModelFactory = balanceViewModelFactory @@ -335,7 +339,38 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { } func vote() { - wireframe.showVote(from: view, referendum: referendum) + guard let wallet = wallet, let view = view else { + return + } + + if wallet.fetch(for: chain.accountRequest()) != nil { + wireframe.showVote(from: view, referendum: referendum) + } else if accountManagementFilter.accountManagementSupports(wallet: wallet, for: chain) { + let message = R.string.localizable.commonChainCrowdloanAccountMissingMessage( + chain.name, + preferredLanguages: selectedLocale.rLanguages + ) + + wireframe.presentAddAccount( + from: view, + chainName: chain.name, + message: message, + locale: selectedLocale + ) { [weak self] in + guard let wallet = self?.wallet else { + return + } + + self?.wireframe.showWalletDetails(from: self?.view, wallet: wallet) + } + } else { + wireframe.presentNoAccountSupport( + from: view, + walletType: wallet.type, + chainName: chain.name, + locale: selectedLocale + ) + } } func showProposerDetails() { @@ -402,6 +437,10 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { } extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol { + func didReceiveWallet(_ wallet: MetaAccountModel?) { + self.wallet = wallet + } + func didReceiveReferendum(_ referendum: ReferendumLocal) { self.referendum = referendum diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index c29470e372..5247d42e2f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -34,6 +34,7 @@ protocol ReferendumDetailsInteractorInputProtocol: AnyObject { } protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { + func didReceiveWallet(_ wallet: MetaAccountModel?) func didReceiveReferendum(_ referendum: ReferendumLocal) func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) func didReceiveAccountVotes(_ votes: ReferendumAccountVoteLocal?) @@ -47,7 +48,7 @@ protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { } protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, - AddressOptionsPresentable, WebPresentable { + AddressOptionsPresentable, WebPresentable, NoAccountSupportPresentable { func showFullDetails( from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal, @@ -70,4 +71,6 @@ protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, ) func showDApp(from view: ReferendumDetailsViewProtocol?, url: URL) + + func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index e28214dac3..ff06d60211 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -54,6 +54,7 @@ struct ReferendumDetailsViewFactory { let presenter = ReferendumDetailsPresenter( referendum: referendum, chain: chain, + accountManagementFilter: AccountManagementFilter(), accountVotes: accountVotes, metadata: metadata, interactor: interactor, @@ -86,9 +87,7 @@ struct ReferendumDetailsViewFactory { currencyManager: CurrencyManagerProtocol, state: GovernanceSharedState ) -> ReferendumDetailsInteractor? { - guard - let chain = state.settings.value, - let selectedAccount = SelectedWalletSettings.shared.value.fetch(for: chain.accountRequest()) else { + guard let chain = state.settings.value else { return nil } @@ -120,7 +119,7 @@ struct ReferendumDetailsViewFactory { return ReferendumDetailsInteractor( referendum: referendum, - selectedAccount: selectedAccount, + walletSettings: SelectedWalletSettings.shared, chain: chain, actionDetailsOperationFactory: actionDetailsFactory, connection: connection, @@ -132,6 +131,7 @@ struct ReferendumDetailsViewFactory { govMetadataLocalSubscriptionFactory: state.govMetadataLocalSubscriptionFactory, referendumsSubscriptionFactory: subscriptionFactory, dAppsProvider: dAppsProvider, + eventCenter: EventCenter.shared, currencyManager: currencyManager, operationQueue: OperationManagerFacade.sharedDefaultQueue ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index 11fb4b8175..b826e4c1f0 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -91,4 +91,12 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { view?.controller.navigationController?.pushViewController(browser.controller, animated: true) } + + func showWalletDetails(from view: ControllerBackedProtocol?, wallet: MetaAccountModel) { + guard let accountManagementView = AccountManagementViewFactory.createView(for: wallet.identifier) else { + return + } + + view?.controller.navigationController?.pushViewController(accountManagementView.controller, animated: true) + } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 0cfa5240d6..fac2a37a23 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -119,6 +119,8 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani if let accountId = accountId { subscribeAccountVotes(for: accountId) + } else { + presenter?.didReceiveVoting(.init(value: nil, blockHash: nil)) } } diff --git a/novawallet/Modules/Vote/Parent/VotePresenter.swift b/novawallet/Modules/Vote/Parent/VotePresenter.swift index 40b0269293..dfa015ba6f 100644 --- a/novawallet/Modules/Vote/Parent/VotePresenter.swift +++ b/novawallet/Modules/Vote/Parent/VotePresenter.swift @@ -27,7 +27,11 @@ final class VotePresenter { return } - let viewModel = walletSwitchViewModelFactory.createViewModel(from: wallet.walletIdenticonData(), walletType: wallet.type) + let viewModel = walletSwitchViewModelFactory.createViewModel( + from: wallet.walletIdenticonData(), + walletType: wallet.type + ) + view?.didSwitchWallet(with: viewModel) } } From 4ae0d812cbd9e8209844e76903c0efc522b83cc6 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 11:38:04 +0500 Subject: [PATCH 186/229] refactoring --- .../ReferendumDetailsInteractor.swift | 31 +++---------------- .../ReferendumDetailsPresenter.swift | 10 +++--- .../ReferendumDetailsProtocols.swift | 1 - .../ReferendumDetailsViewFactory.swift | 9 ++++-- 4 files changed, 15 insertions(+), 36 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 6324af0731..e7fac9b7a2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -8,7 +8,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { private(set) var referendum: ReferendumLocal private(set) var actionDetails: ReferendumActionLocal? - let walletSettings: SelectedWalletSettings + let selectedAccount: ChainAccountResponse? let chain: ChainModel let actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol let connection: JSONRPCEngine @@ -20,7 +20,6 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { let referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol let dAppsProvider: AnySingleValueProvider - let eventCenter: EventCenterProtocol let operationQueue: OperationQueue private var priceProvider: AnySingleValueProvider? @@ -34,7 +33,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { init( referendum: ReferendumLocal, - walletSettings: SelectedWalletSettings, + selectedAccount: ChainAccountResponse?, chain: ChainModel, actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol, connection: JSONRPCEngine, @@ -46,12 +45,11 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol, referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol, dAppsProvider: AnySingleValueProvider, - eventCenter: EventCenterProtocol, currencyManager: CurrencyManagerProtocol, operationQueue: OperationQueue ) { self.referendum = referendum - self.walletSettings = walletSettings + self.selectedAccount = selectedAccount self.chain = chain self.actionDetailsOperationFactory = actionDetailsOperationFactory self.connection = connection @@ -63,7 +61,6 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { self.govMetadataLocalSubscriptionFactory = govMetadataLocalSubscriptionFactory self.referendumsSubscriptionFactory = referendumsSubscriptionFactory self.dAppsProvider = dAppsProvider - self.eventCenter = eventCenter self.operationQueue = operationQueue self.currencyManager = currencyManager } @@ -76,19 +73,11 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { referendumsSubscriptionFactory.unsubscribeFromReferendum(self, referendumIndex: referendum.index) - if let accountId = selectedAccountId() { + if let accountId = selectedAccount?.accountId { referendumsSubscriptionFactory.unsubscribeFromAccountVotes(self, accountId: accountId) } } - private func selectedAccountId() -> AccountId? { - walletSettings.value?.fetch(for: chain.accountRequest())?.accountId - } - - private func provideSelectedWallet() { - presenter?.didReceiveWallet(walletSettings.value) - } - private func subscribeReferendum() { referendumsSubscriptionFactory.unsubscribeFromReferendum(self, referendumIndex: referendum.index) @@ -111,7 +100,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { } private func subscribeAccountVotes() { - guard let accountId = selectedAccountId() else { + guard let accountId = selectedAccount?.accountId else { presenter?.didReceiveAccountVotes(nil) return } @@ -299,12 +288,9 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { extension ReferendumDetailsInteractor: ReferendumDetailsInteractorInputProtocol { func setup() { - provideSelectedWallet() makeSubscriptions() updateActionDetails() subscribeDApps() - - eventCenter.add(observer: self, dispatchIn: .main) } func remakeDAppsSubscription() { @@ -385,10 +371,3 @@ extension ReferendumDetailsInteractor: SelectedCurrencyDepending { } } } - -extension ReferendumDetailsInteractor: EventVisitorProtocol { - func processSelectedAccountChanged(event _: SelectedAccountChanged) { - provideSelectedWallet() - makeAccountBasedSubscriptions() - } -} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 9c75b9fd1e..de038ea624 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -15,11 +15,11 @@ final class ReferendumDetailsPresenter { let displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol let statusViewModelFactory: ReferendumStatusViewModelFactoryProtocol let accountManagementFilter: AccountManagementFilterProtocol + let wallet: MetaAccountModel let chain: ChainModel let logger: LoggerProtocol - private var wallet: MetaAccountModel? private var referendum: ReferendumLocal private var actionDetails: ReferendumActionLocal? private var accountVotes: ReferendumAccountVoteLocal? @@ -39,6 +39,7 @@ final class ReferendumDetailsPresenter { init( referendum: ReferendumLocal, chain: ChainModel, + wallet: MetaAccountModel, accountManagementFilter: AccountManagementFilterProtocol, accountVotes: ReferendumAccountVoteLocal?, metadata: ReferendumMetadataLocal?, @@ -57,6 +58,7 @@ final class ReferendumDetailsPresenter { ) { self.interactor = interactor self.wireframe = wireframe + self.wallet = wallet self.accountManagementFilter = accountManagementFilter self.referendumViewModelFactory = referendumViewModelFactory self.referendumStringsFactory = referendumStringsFactory @@ -339,7 +341,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { } func vote() { - guard let wallet = wallet, let view = view else { + guard let view = view else { return } @@ -437,10 +439,6 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { } extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol { - func didReceiveWallet(_ wallet: MetaAccountModel?) { - self.wallet = wallet - } - func didReceiveReferendum(_ referendum: ReferendumLocal) { self.referendum = referendum diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 5247d42e2f..6eca01a943 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -34,7 +34,6 @@ protocol ReferendumDetailsInteractorInputProtocol: AnyObject { } protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { - func didReceiveWallet(_ wallet: MetaAccountModel?) func didReceiveReferendum(_ referendum: ReferendumLocal) func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) func didReceiveAccountVotes(_ votes: ReferendumAccountVoteLocal?) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index ff06d60211..f11258b90d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -18,7 +18,8 @@ struct ReferendumDetailsViewFactory { state: state ), let chain = state.settings.value, - let assetInfo = chain.utilityAssetDisplayInfo() else { + let assetInfo = chain.utilityAssetDisplayInfo(), + let wallet = SelectedWalletSettings.shared.value else { return nil } @@ -54,6 +55,7 @@ struct ReferendumDetailsViewFactory { let presenter = ReferendumDetailsPresenter( referendum: referendum, chain: chain, + wallet: wallet, accountManagementFilter: AccountManagementFilter(), accountVotes: accountVotes, metadata: metadata, @@ -91,6 +93,8 @@ struct ReferendumDetailsViewFactory { return nil } + let selectedAccount = SelectedWalletSettings.shared.value?.fetch(for: chain.accountRequest()) + let chainRegistry = state.chainRegistry guard @@ -119,7 +123,7 @@ struct ReferendumDetailsViewFactory { return ReferendumDetailsInteractor( referendum: referendum, - walletSettings: SelectedWalletSettings.shared, + selectedAccount: selectedAccount, chain: chain, actionDetailsOperationFactory: actionDetailsFactory, connection: connection, @@ -131,7 +135,6 @@ struct ReferendumDetailsViewFactory { govMetadataLocalSubscriptionFactory: state.govMetadataLocalSubscriptionFactory, referendumsSubscriptionFactory: subscriptionFactory, dAppsProvider: dAppsProvider, - eventCenter: EventCenter.shared, currencyManager: currencyManager, operationQueue: OperationManagerFacade.sharedDefaultQueue ) From 0cacf32d4f1096002be9a167325263dac491ecd7 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 11:59:22 +0500 Subject: [PATCH 187/229] fix evm accounts --- .../ConvictionVoting/ConvictionVoting.swift | 2 +- .../ConvictionVotingForKey.swift | 2 +- .../Types/Democracy/DemocracyVoting.swift | 2 +- .../ReferendumVotersPresenter.swift | 85 ++++++++++--------- 4 files changed, 49 insertions(+), 42 deletions(-) diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift index d1ef615709..1991955e73 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVoting.swift @@ -262,7 +262,7 @@ enum ConvictionVoting { @StringCodable var balance: BigUInt /// The account to which the voting power is delegated. - let target: AccountId + @BytesCodable var target: AccountId /** * The conviction with which the voting power is delegated. When this gets undelegated, the diff --git a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingForKey.swift b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingForKey.swift index a6a79c7987..84fbb27d0d 100644 --- a/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingForKey.swift +++ b/novawallet/Common/Substrate/Types/ConvictionVoting/ConvictionVotingForKey.swift @@ -16,7 +16,7 @@ extension ConvictionVoting { ) } - accountId = try jsonList[0].map(to: AccountId.self, with: context) + accountId = try jsonList[0].map(to: BytesCodable.self, with: context).wrappedValue trackId = try jsonList[1].map(to: StringScaleMapper.self, with: context).value } } diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyVoting.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyVoting.swift index b7959ec6b6..02e4cadc00 100644 --- a/novawallet/Common/Substrate/Types/Democracy/DemocracyVoting.swift +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyVoting.swift @@ -37,7 +37,7 @@ extension Democracy { ) } - accountId = try jsonList[0].map(to: AccountId.self, with: context) + accountId = try jsonList[0].map(to: BytesCodable.self, with: context).wrappedValue } } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift index b232628e7d..396d9b0c31 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersPresenter.swift @@ -38,6 +38,50 @@ final class ReferendumVotersPresenter { self.localizationManager = localizationManager } + private func createViewModel( + _ model: ReferendumVotersModel, + voter: ReferendumVoterLocal + ) -> ReferendumVotersViewModel? { + guard let address = try? voter.accountId.toAddress(using: chain.chainFormat) else { + return nil + } + + let displayAddressViewModel: DisplayAddressViewModel + + if let displayName = model.identites[address]?.displayName { + let displayAddress = DisplayAddress(address: address, username: displayName) + displayAddressViewModel = displayAddressFactory.createViewModel(from: displayAddress) + } else { + displayAddressViewModel = displayAddressFactory.createViewModel(from: address) + } + + let amountInPlank: BigUInt + let votes: BigUInt + + switch type { + case .ayes: + amountInPlank = voter.vote.ayeBalance + votes = voter.vote.ayes + case .nays: + amountInPlank = voter.vote.nayBalance + votes = voter.vote.nays + } + + let votesString = stringFactory.createVotes(from: votes, chain: chain, locale: selectedLocale) + let details = stringFactory.createVotesDetails( + from: amountInPlank, + conviction: voter.vote.conviction, + chain: chain, + locale: selectedLocale + ) + + return ReferendumVotersViewModel( + displayAddress: displayAddressViewModel, + votes: votesString ?? "", + preConviction: details ?? "" + ) + } + private func updateView() { guard let model = model else { return @@ -60,44 +104,7 @@ final class ReferendumVotersPresenter { } } .compactMap { voter in - guard let address = try? voter.accountId.toAddress(using: chain.chainFormat) else { - return nil - } - - let displayAddressViewModel: DisplayAddressViewModel - - if let displayName = model.identites[address]?.displayName { - let displayAddress = DisplayAddress(address: address, username: displayName) - displayAddressViewModel = displayAddressFactory.createViewModel(from: displayAddress) - } else { - displayAddressViewModel = displayAddressFactory.createViewModel(from: address) - } - - let amountInPlank: BigUInt - let votes: BigUInt - - switch type { - case .ayes: - amountInPlank = voter.vote.ayeBalance - votes = voter.vote.ayes - case .nays: - amountInPlank = voter.vote.nayBalance - votes = voter.vote.nays - } - - let votesString = stringFactory.createVotes(from: votes, chain: chain, locale: selectedLocale) - let details = stringFactory.createVotesDetails( - from: amountInPlank, - conviction: voter.vote.conviction, - chain: chain, - locale: selectedLocale - ) - - return ReferendumVotersViewModel( - displayAddress: displayAddressViewModel, - votes: votesString ?? "", - preConviction: details ?? "" - ) + createViewModel(model, voter: voter) } view?.didReceiveViewModels(.loaded(value: viewModels)) @@ -138,7 +145,7 @@ extension ReferendumVotersPresenter: ReferendumVotersInteractorOutputProtocol { switch error { case .votersFetchFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in - self?.updateView() + self?.interactor.refreshVoters() } } } From 384a3f6d7685554a7b45e0ea87e22c75f920a3b9 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 12:54:26 +0500 Subject: [PATCH 188/229] show no track if there is single track in the network --- .../Governance/Model/ReferendumLocal.swift | 1 + .../Operation/Gov1LocalMappingFactory.swift | 6 ++++- .../Operation/Gov2LocalMappingFactory.swift | 12 +++++++-- .../ReferendumDetailsPresenter.swift | 12 +++++++-- .../ViewModel/ReferendumsModelFactory.swift | 25 +++++++++++-------- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index ebd3ce1be0..0893588686 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -245,4 +245,5 @@ enum ReferendumStateLocal { struct GovernanceTrackLocal { let trackId: UInt16 let name: String + let totalTracksCount: Int } diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift index 107b1b226b..417c229018 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift @@ -7,7 +7,11 @@ final class Gov1LocalMappingFactory { index: Referenda.ReferendumIndex, additionalInfo: Gov1OperationFactory.AdditionalInfo ) -> ReferendumLocal { - let track = GovernanceTrackLocal(trackId: Gov1OperationFactory.trackId, name: Gov1OperationFactory.trackName) + let track = GovernanceTrackLocal( + trackId: Gov1OperationFactory.trackId, + name: Gov1OperationFactory.trackName, + totalTracksCount: 1 + ) let submitted = referendum.end - additionalInfo.votingPeriod diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift index 9dbb261f9e..8eb5c58239 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift @@ -29,7 +29,11 @@ final class Gov2LocalMappingFactory { supportFunction: supportFunction ) - let localTrack = GovernanceTrackLocal(trackId: status.track, name: track.name) + let localTrack = GovernanceTrackLocal( + trackId: status.track, + name: track.name, + totalTracksCount: additionalInfo.tracks.count + ) let deposit = deposit(from: status.submissionDeposit, decision: status.decisionDeposit) @@ -75,7 +79,11 @@ final class Gov2LocalMappingFactory { supportFunction: supportFunction ) - let localTrack = GovernanceTrackLocal(trackId: status.track, name: track.name) + let localTrack = GovernanceTrackLocal( + trackId: status.track, + name: track.name, + totalTracksCount: additionalInfo.tracks.count + ) let inQueuePosition: ReferendumStateLocal.InQueuePosition? diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index de038ea624..5e544c1441 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -85,8 +85,16 @@ final class ReferendumDetailsPresenter { from: referendum.index as NSNumber ) - let trackViewModel = referendum.track.map { - ReferendumTrackType.createViewModel(from: $0.name, chain: chain, locale: selectedLocale) + // display track name only if there is more than 1 track in the network + let trackViewModel: ReferendumInfoView.Track? + if let track = referendum.track, track.totalTracksCount > 1 { + trackViewModel = ReferendumTrackType.createViewModel( + from: track.name, + chain: chain, + locale: selectedLocale + ) + } else { + trackViewModel = nil } let viewModel = TrackTagsView.Model(titleIcon: trackViewModel, referendumNumber: referendumIndex) diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index ad36e0b321..8619aaae06 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -169,11 +169,7 @@ final class ReferendumsModelFactory { locale: locale ) - let track = ReferendumTrackType.createViewModel( - from: model.track.name, - chain: params.chainInfo.chain, - locale: locale - ) + let track = createTrackViewModel(from: model.track, params: params, locale: locale) let referendumNumber = localizedIndexFormatter.value(for: locale).string( from: NSNumber(value: params.referendum.index) @@ -238,6 +234,19 @@ final class ReferendumsModelFactory { ) } + private func createTrackViewModel( + from track: GovernanceTrackLocal, + params: StatusParams, + locale: Locale + ) -> ReferendumInfoView.Track? { + // display track name if more than 1 track in the network + guard track.totalTracksCount > 1 else { + return nil + } + + return ReferendumTrackType.createViewModel(from: track.name, chain: params.chainInfo.chain, locale: locale) + } + private func provideDecidingReferendumCellViewModel( _ model: ReferendumStateLocal.Deciding, params: StatusParams, @@ -280,11 +289,7 @@ final class ReferendumsModelFactory { locale: locale ) - let track = ReferendumTrackType.createViewModel( - from: model.track.name, - chain: params.chainInfo.chain, - locale: locale - ) + let track = createTrackViewModel(from: model.track, params: params, locale: locale) let indexFormatter = localizedIndexFormatter.value(for: locale) let referendumNumber = indexFormatter.string(from: NSNumber(value: params.referendum.index)) From 9bdefd934692101b5eb83b0902e77015b496cf15 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 14:31:23 +0500 Subject: [PATCH 189/229] try fix link --- .../Modules/Vote/Governance/View/MarkdownViewContainer.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift b/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift index eeb1d3b688..820dd842da 100644 --- a/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift +++ b/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift @@ -71,6 +71,7 @@ final class MarkdownViewContainer: UIView, AnyCancellableCleaning { textView.textContainerInset = .zero textView.textContainer.lineFragmentPadding = 0 textView.roundAllCorners = true + textView.dataDetectorTypes = [.link] textView.backgroundColor = .clear From fcd290f0c0223b6ce7103adf48cd7bf35e27f22b Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 15:40:00 +0500 Subject: [PATCH 190/229] add enactmet fetch --- novawallet.xcodeproj/project.pbxproj | 24 ++++-- .../{ => Fetch}/Gov1LocalMappingFactory.swift | 0 .../Gov1OperationFactory+Protocol.swift | 24 ++++-- .../{ => Fetch}/Gov1OperationFactory.swift | 43 +++++++++-- .../{ => Fetch}/Gov2LocalMappingFactory.swift | 0 .../Gov2OperationFactory+Protocol.swift | 0 .../{ => Fetch}/Gov2OperationFactory.swift | 71 ++++------------- .../Fetch/GovernanceOperationFactory.swift | 76 +++++++++++++++++++ 8 files changed, 163 insertions(+), 75 deletions(-) rename novawallet/Modules/Vote/Governance/Operation/{ => Fetch}/Gov1LocalMappingFactory.swift (100%) rename novawallet/Modules/Vote/Governance/Operation/{ => Fetch}/Gov1OperationFactory+Protocol.swift (91%) rename novawallet/Modules/Vote/Governance/Operation/{ => Fetch}/Gov1OperationFactory.swift (75%) rename novawallet/Modules/Vote/Governance/Operation/{ => Fetch}/Gov2LocalMappingFactory.swift (100%) rename novawallet/Modules/Vote/Governance/Operation/{ => Fetch}/Gov2OperationFactory+Protocol.swift (100%) rename novawallet/Modules/Vote/Governance/Operation/{ => Fetch}/Gov2OperationFactory.swift (77%) create mode 100644 novawallet/Modules/Vote/Governance/Operation/Fetch/GovernanceOperationFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 4324859436..5decc62473 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1226,6 +1226,7 @@ 8476D39D27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D39C27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift */; }; 8476D39F27F4582A004D9A7A /* DAppMetamaskPhishingDetectedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D39E27F4582A004D9A7A /* DAppMetamaskPhishingDetectedState.swift */; }; 8476D3A127F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D3A027F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift */; }; + 84770F22291E58AE00852A33 /* GovernanceOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84770F21291E58AE00852A33 /* GovernanceOperationFactory.swift */; }; 8477DAA32888329800129B45 /* watchOnlyPreset.json in Resources */ = {isa = PBXBuildFile; fileRef = 8477DAA22888329800129B45 /* watchOnlyPreset.json */; }; 8477DAA6288832CB00129B45 /* WatchOnlyPresetRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8477DAA5288832CB00129B45 /* WatchOnlyPresetRepository.swift */; }; 84786DA825F9F58E0089DFF7 /* EraValidatorService+Fetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84786DA725F9F58E0089DFF7 /* EraValidatorService+Fetch.swift */; }; @@ -4215,6 +4216,7 @@ 8476D39C27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PhishingSiteVerifier+Init.swift"; sourceTree = ""; }; 8476D39E27F4582A004D9A7A /* DAppMetamaskPhishingDetectedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppMetamaskPhishingDetectedState.swift; sourceTree = ""; }; 8476D3A027F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserPhishingDetectedState.swift; sourceTree = ""; }; + 84770F21291E58AE00852A33 /* GovernanceOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceOperationFactory.swift; sourceTree = ""; }; 8477DAA22888329800129B45 /* watchOnlyPreset.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = watchOnlyPreset.json; sourceTree = ""; }; 8477DAA5288832CB00129B45 /* WatchOnlyPresetRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchOnlyPresetRepository.swift; sourceTree = ""; }; 84786DA725F9F58E0089DFF7 /* EraValidatorService+Fetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EraValidatorService+Fetch.swift"; sourceTree = ""; }; @@ -8881,6 +8883,20 @@ path = ModalAlert; sourceTree = ""; }; + 84770F23291E590800852A33 /* Fetch */ = { + isa = PBXGroup; + children = ( + 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, + 8438432D2913B3150048595C /* Gov1OperationFactory.swift */, + 84770F21291E58AE00852A33 /* GovernanceOperationFactory.swift */, + 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */, + 845B07F4291627A3005785D3 /* Gov1OperationFactory+Protocol.swift */, + 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */, + 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, + ); + path = Fetch; + sourceTree = ""; + }; 847999B22888B46300D1BAD2 /* Address */ = { isa = PBXGroup; children = ( @@ -10446,16 +10462,11 @@ 84A1742528ED60610096F943 /* Operation */ = { isa = PBXGroup; children = ( + 84770F23291E590800852A33 /* Fetch */, 845B080E2918D64B005785D3 /* Extrinsics */, 845B08022918C2E5005785D3 /* Action */, 843461F1290D370000379936 /* Locks */, 84A1742628ED607B0096F943 /* GovernanceOperationProtocols.swift */, - 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, - 8438432D2913B3150048595C /* Gov1OperationFactory.swift */, - 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */, - 845B07F4291627A3005785D3 /* Gov1OperationFactory+Protocol.swift */, - 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */, - 84DD49F328EE91ED00B804F3 /* Gov2LocalMappingFactory.swift */, 8425D0E928FE9A45003B782A /* GovernanceExtrinsicFactoryProtocol.swift */, ); path = Operation; @@ -17403,6 +17414,7 @@ 3A4743C7C74BE4F74F6390F6 /* ReferendumFullDescriptionViewLayout.swift in Sources */, F8C0CA3DDBCB5E509295F099 /* ReferendumFullDescriptionViewFactory.swift in Sources */, 9DE1757D047A4D1E97913774 /* GovernanceUnlockConfirmProtocols.swift in Sources */, + 84770F22291E58AE00852A33 /* GovernanceOperationFactory.swift in Sources */, 2272FB0A01000A46D097634E /* GovernanceUnlockConfirmWireframe.swift in Sources */, A3BDFA01A32B6C7463E6EFFA /* GovernanceUnlockConfirmPresenter.swift in Sources */, 62649D3FB6AACB508872C67A /* GovernanceUnlockConfirmInteractor.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift similarity index 100% rename from novawallet/Modules/Vote/Governance/Operation/Gov1LocalMappingFactory.swift rename to novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory+Protocol.swift similarity index 91% rename from novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift rename to novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory+Protocol.swift index 6b75aed0e4..3e1749e652 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory+Protocol.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory+Protocol.swift @@ -22,6 +22,15 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { referendumWrapper.addDependency(operations: [codingFactoryOperation]) + let enactmentsWrapper = createEnacmentTimeFetchWrapper( + dependingOn: referendumWrapper.targetOperation, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: nil + ) + + enactmentsWrapper.addDependency(wrapper: referendumWrapper) + let additionalWrapper = createAdditionalInfoWrapper( dependingOn: codingFactoryOperation, connection: connection, @@ -32,16 +41,18 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { let mapOperation = createReferendumMapOperation( dependingOn: referendumWrapper.targetOperation, - additionalInfoOperation: additionalWrapper.targetOperation + additionalInfoOperation: additionalWrapper.targetOperation, + enactmentsOperation: enactmentsWrapper.targetOperation ) mapOperation.addDependency(additionalWrapper.targetOperation) mapOperation.addDependency(referendumWrapper.targetOperation) + mapOperation.addDependency(enactmentsWrapper.targetOperation) - return .init( - targetOperation: mapOperation, - dependencies: [codingFactoryOperation] + referendumWrapper.allOperations + additionalWrapper.allOperations - ) + let dependencies = [codingFactoryOperation] + referendumWrapper.allOperations + + enactmentsWrapper.allOperations + additionalWrapper.allOperations + + return .init(targetOperation: mapOperation, dependencies: dependencies) } func fetchReferendumWrapper( @@ -68,7 +79,8 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { let mergeOperation = createReferendumMapOperation( dependingOn: referendumOperation, - additionalInfoOperation: additionalInfoWrapper.targetOperation + additionalInfoOperation: additionalInfoWrapper.targetOperation, + enactmentsOperation: <#T##BaseOperation<[ReferendumIdLocal : BlockNumber]>#> ) mergeOperation.addDependency(referendumOperation) diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift similarity index 75% rename from novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift rename to novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift index 6c1fb849bc..a9ae457507 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov1OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift @@ -3,7 +3,7 @@ import RobinHood import BigInt import SubstrateSdk -final class Gov1OperationFactory { +final class Gov1OperationFactory: GovernanceOperationFactory { static let trackName: String = "root" static let trackId: Referenda.TrackId = 0 @@ -14,12 +14,39 @@ final class Gov1OperationFactory { let block: BlockNumber } - let requestFactory: StorageRequestFactoryProtocol - let operationQueue: OperationQueue + func createEnacmentTimeFetchWrapper( + dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: Democracy.ReferendumInfo]>, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper<[ReferendumIdLocal: BlockNumber]> { + let approvedReferendumsOperation = ClosureOperation> { + let referendums = try referendumOperation.extractNoCancellableResultData() + + let items: [Referenda.ReferendumIndex] = referendums.compactMap { keyValue in + switch keyValue.value { + case let .finished(status): + return status.approved ? keyValue.key.referendumIndex : nil + default: + return nil + } + } + + return Set(items) + } + + let fetchWrapper = createEnacmentTimeFetchWrapper( + dependingOn: approvedReferendumsOperation, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + fetchWrapper.addDependency(operations: [approvedReferendumsOperation]) - init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { - self.requestFactory = requestFactory - self.operationQueue = operationQueue + let dependencies = [approvedReferendumsOperation] + fetchWrapper.dependencies + + return CompoundOperationWrapper(targetOperation: fetchWrapper.targetOperation, dependencies: dependencies) } func createAdditionalInfoWrapper( @@ -88,7 +115,9 @@ final class Gov1OperationFactory { func createReferendumMapOperation( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: Democracy.ReferendumInfo]>, - additionalInfoOperation: BaseOperation + additionalInfoOperation: BaseOperation, + enactmentsOperation _: BaseOperation<[ReferendumIdLocal: BlockNumber]> + ) -> BaseOperation<[ReferendumLocal]> { ClosureOperation<[ReferendumLocal]> { let remoteReferendums = try referendumOperation.extractNoCancellableResultData() diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2LocalMappingFactory.swift similarity index 100% rename from novawallet/Modules/Vote/Governance/Operation/Gov2LocalMappingFactory.swift rename to novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2LocalMappingFactory.swift diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2OperationFactory+Protocol.swift similarity index 100% rename from novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory+Protocol.swift rename to novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2OperationFactory+Protocol.swift diff --git a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2OperationFactory.swift similarity index 77% rename from novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift rename to novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2OperationFactory.swift index ee56e89536..a992940c1a 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2OperationFactory.swift @@ -3,87 +3,46 @@ import SubstrateSdk import RobinHood import BigInt -final class Gov2OperationFactory { +final class Gov2OperationFactory: GovernanceOperationFactory { struct AdditionalInfo { let tracks: [Referenda.TrackId: Referenda.TrackInfo] let totalIssuance: BigUInt let undecidingTimeout: Moment } - struct SchedulerTaskName: Encodable { - let index: Referenda.ReferendumIndex - - func encode(to encoder: Encoder) throws { - let scaleEncoder = ScaleEncoder() - "assembly".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } - try "enactment".encode(scaleEncoder: scaleEncoder) - try index.encode(scaleEncoder: scaleEncoder) - - let data = try scaleEncoder.encode().blake2b32() - - var container = encoder.singleValueContainer() - try container.encode(BytesCodable(wrappedValue: data)) - } - } - - let requestFactory: StorageRequestFactoryProtocol - let operationQueue: OperationQueue - - init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { - self.requestFactory = requestFactory - self.operationQueue = operationQueue - } - func createEnacmentTimeFetchWrapper( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockHash: Data? ) -> CompoundOperationWrapper<[ReferendumIdLocal: BlockNumber]> { - let keysClosure: () throws -> [SchedulerTaskName] = { + let approvedReferendumsOperation = ClosureOperation> { let referendums = try referendumOperation.extractNoCancellableResultData() - return referendums.compactMap { keyValue in + let items: [Referenda.ReferendumIndex] = referendums.compactMap { keyValue in switch keyValue.value { case .approved: - return SchedulerTaskName(index: keyValue.key.referendumIndex) + return keyValue.key.referendumIndex default: return nil } } - } - - let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - let enactmentWrapper: CompoundOperationWrapper<[StorageResponse]> = - requestFactory.queryItems( - engine: connection, - keyParams: keysClosure, - factory: { try codingFactoryOperation.extractNoCancellableResultData() }, - storagePath: OnChainScheduler.lookupTaskPath, - at: blockHash - ) - - enactmentWrapper.addDependency(operations: [codingFactoryOperation]) - - let mapOperation = ClosureOperation<[ReferendumIdLocal: BlockNumber]> { - let keys = try keysClosure() - let results = try enactmentWrapper.targetOperation.extractNoCancellableResultData() - - return zip(keys, results).reduce(into: [ReferendumIdLocal: BlockNumber]()) { accum, keyResult in - guard let when = keyResult.1.value?.when else { - return - } - - accum[ReferendumIdLocal(keyResult.0.index)] = when - } + return Set(items) } - mapOperation.addDependency(enactmentWrapper.targetOperation) + let fetchWrapper = createEnacmentTimeFetchWrapper( + dependingOn: approvedReferendumsOperation, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + fetchWrapper.addDependency(operations: [approvedReferendumsOperation]) - let dependencies = [codingFactoryOperation] + enactmentWrapper.allOperations + let dependencies = [approvedReferendumsOperation] + fetchWrapper.dependencies - return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + return CompoundOperationWrapper(targetOperation: fetchWrapper.targetOperation, dependencies: dependencies) } func createReferendumMapOperation( diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/GovernanceOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/GovernanceOperationFactory.swift new file mode 100644 index 0000000000..ac925c4942 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/GovernanceOperationFactory.swift @@ -0,0 +1,76 @@ +import Foundation +import SubstrateSdk +import RobinHood + +class GovernanceOperationFactory { + struct SchedulerTaskName: Encodable { + let index: Referenda.ReferendumIndex + + func encode(to encoder: Encoder) throws { + let scaleEncoder = ScaleEncoder() + "assembly".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } + try "enactment".encode(scaleEncoder: scaleEncoder) + try index.encode(scaleEncoder: scaleEncoder) + + let data = try scaleEncoder.encode().blake2b32() + + var container = encoder.singleValueContainer() + try container.encode(BytesCodable(wrappedValue: data)) + } + } + + let requestFactory: StorageRequestFactoryProtocol + let operationQueue: OperationQueue + + init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { + self.requestFactory = requestFactory + self.operationQueue = operationQueue + } + + func createEnacmentTimeFetchWrapper( + dependingOn referendumOperation: BaseOperation>, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper<[ReferendumIdLocal: BlockNumber]> { + let keysClosure: () throws -> [SchedulerTaskName] = { + let referendums = try referendumOperation.extractNoCancellableResultData() + + return Array(referendums).map { key in + SchedulerTaskName(index: key) + } + } + + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let enactmentWrapper: CompoundOperationWrapper<[StorageResponse]> = + requestFactory.queryItems( + engine: connection, + keyParams: keysClosure, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: OnChainScheduler.lookupTaskPath, + at: blockHash + ) + + enactmentWrapper.addDependency(operations: [codingFactoryOperation]) + + let mapOperation = ClosureOperation<[ReferendumIdLocal: BlockNumber]> { + let keys = try keysClosure() + let results = try enactmentWrapper.targetOperation.extractNoCancellableResultData() + + return zip(keys, results).reduce(into: [ReferendumIdLocal: BlockNumber]()) { accum, keyResult in + guard let when = keyResult.1.value?.when else { + return + } + + accum[ReferendumIdLocal(keyResult.0.index)] = when + } + } + + mapOperation.addDependency(enactmentWrapper.targetOperation) + + let dependencies = [codingFactoryOperation] + enactmentWrapper.allOperations + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } +} From 83244fe74573c4eb3dec4cb213d795c6a9c32d31 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 17:24:42 +0500 Subject: [PATCH 191/229] improve enactment time calculation for gov1 --- novawallet.xcodeproj/project.pbxproj | 4 - .../Fetch/Gov1LocalMappingFactory.swift | 19 +++-- .../Fetch/Gov1OperationFactory+Protocol.swift | 14 +++- .../Fetch/Gov1OperationFactory.swift | 81 ++++++++++++++----- .../Fetch/Gov2OperationFactory.swift | 71 ++++++++++++---- .../Fetch/GovernanceOperationFactory.swift | 76 ----------------- 6 files changed, 143 insertions(+), 122 deletions(-) delete mode 100644 novawallet/Modules/Vote/Governance/Operation/Fetch/GovernanceOperationFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 5decc62473..09a582fb12 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1226,7 +1226,6 @@ 8476D39D27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D39C27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift */; }; 8476D39F27F4582A004D9A7A /* DAppMetamaskPhishingDetectedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D39E27F4582A004D9A7A /* DAppMetamaskPhishingDetectedState.swift */; }; 8476D3A127F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D3A027F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift */; }; - 84770F22291E58AE00852A33 /* GovernanceOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84770F21291E58AE00852A33 /* GovernanceOperationFactory.swift */; }; 8477DAA32888329800129B45 /* watchOnlyPreset.json in Resources */ = {isa = PBXBuildFile; fileRef = 8477DAA22888329800129B45 /* watchOnlyPreset.json */; }; 8477DAA6288832CB00129B45 /* WatchOnlyPresetRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8477DAA5288832CB00129B45 /* WatchOnlyPresetRepository.swift */; }; 84786DA825F9F58E0089DFF7 /* EraValidatorService+Fetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84786DA725F9F58E0089DFF7 /* EraValidatorService+Fetch.swift */; }; @@ -4216,7 +4215,6 @@ 8476D39C27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PhishingSiteVerifier+Init.swift"; sourceTree = ""; }; 8476D39E27F4582A004D9A7A /* DAppMetamaskPhishingDetectedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppMetamaskPhishingDetectedState.swift; sourceTree = ""; }; 8476D3A027F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserPhishingDetectedState.swift; sourceTree = ""; }; - 84770F21291E58AE00852A33 /* GovernanceOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceOperationFactory.swift; sourceTree = ""; }; 8477DAA22888329800129B45 /* watchOnlyPreset.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = watchOnlyPreset.json; sourceTree = ""; }; 8477DAA5288832CB00129B45 /* WatchOnlyPresetRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchOnlyPresetRepository.swift; sourceTree = ""; }; 84786DA725F9F58E0089DFF7 /* EraValidatorService+Fetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EraValidatorService+Fetch.swift"; sourceTree = ""; }; @@ -8888,7 +8886,6 @@ children = ( 84A1742828ED625D0096F943 /* Gov2OperationFactory.swift */, 8438432D2913B3150048595C /* Gov1OperationFactory.swift */, - 84770F21291E58AE00852A33 /* GovernanceOperationFactory.swift */, 843461E9290C04C400379936 /* Gov2OperationFactory+Protocol.swift */, 845B07F4291627A3005785D3 /* Gov1OperationFactory+Protocol.swift */, 845B07F829162D24005785D3 /* Gov1LocalMappingFactory.swift */, @@ -17414,7 +17411,6 @@ 3A4743C7C74BE4F74F6390F6 /* ReferendumFullDescriptionViewLayout.swift in Sources */, F8C0CA3DDBCB5E509295F099 /* ReferendumFullDescriptionViewFactory.swift in Sources */, 9DE1757D047A4D1E97913774 /* GovernanceUnlockConfirmProtocols.swift in Sources */, - 84770F22291E58AE00852A33 /* GovernanceOperationFactory.swift in Sources */, 2272FB0A01000A46D097634E /* GovernanceUnlockConfirmWireframe.swift in Sources */, A3BDFA01A32B6C7463E6EFFA /* GovernanceUnlockConfirmPresenter.swift in Sources */, 62649D3FB6AACB508872C67A /* GovernanceUnlockConfirmInteractor.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift index 417c229018..261c33b9d4 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift @@ -40,15 +40,14 @@ final class Gov1LocalMappingFactory { private func mapFinished( referendum: Democracy.FinishedStatus, index: Referenda.ReferendumIndex, - additionalInfo: Gov1OperationFactory.AdditionalInfo + additionalInfo _: Gov1OperationFactory.AdditionalInfo, + enactmentBlock: BlockNumber? ) -> ReferendumLocal { if referendum.approved { - let whenEnactment = referendum.end + additionalInfo.enactmentPeriod - - if additionalInfo.block < whenEnactment { + if let enactmentBlock = enactmentBlock { let approved = ReferendumStateLocal.Approved( since: referendum.end, - whenEnactment: whenEnactment, + whenEnactment: enactmentBlock, deposit: nil ) @@ -70,13 +69,19 @@ extension Gov1LocalMappingFactory { func mapRemote( referendum: Democracy.ReferendumInfo, index: Referenda.ReferendumIndex, - additionalInfo: Gov1OperationFactory.AdditionalInfo + additionalInfo: Gov1OperationFactory.AdditionalInfo, + enactmentBlock: BlockNumber? ) -> ReferendumLocal? { switch referendum { case let .ongoing(status): return mapOngoing(referendum: status, index: index, additionalInfo: additionalInfo) case let .finished(status): - return mapFinished(referendum: status, index: index, additionalInfo: additionalInfo) + return mapFinished( + referendum: status, + index: index, + additionalInfo: additionalInfo, + enactmentBlock: enactmentBlock + ) case .unknown: return nil } diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory+Protocol.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory+Protocol.swift index 3e1749e652..7008a131c2 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory+Protocol.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory+Protocol.swift @@ -77,14 +77,24 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { return [referendumIndexKey: remoteReferendum] } + let enactmentsWrapper = createEnacmentTimeFetchWrapper( + dependingOn: referendumOperation, + connection: connection, + runtimeProvider: runtimeProvider, + blockHash: blockHash + ) + + enactmentsWrapper.addDependency(operations: [referendumOperation]) + let mergeOperation = createReferendumMapOperation( dependingOn: referendumOperation, additionalInfoOperation: additionalInfoWrapper.targetOperation, - enactmentsOperation: <#T##BaseOperation<[ReferendumIdLocal : BlockNumber]>#> + enactmentsOperation: enactmentsWrapper.targetOperation ) mergeOperation.addDependency(referendumOperation) mergeOperation.addDependency(additionalInfoWrapper.targetOperation) + mergeOperation.addDependency(enactmentsWrapper.targetOperation) let mapOperation = ClosureOperation { guard let referendum = try mergeOperation.extractNoCancellableResultData().first else { @@ -97,7 +107,7 @@ extension Gov1OperationFactory: ReferendumsOperationFactoryProtocol { mapOperation.addDependency(mergeOperation) let dependencies = [codingFactoryOperation, referendumOperation] + - additionalInfoWrapper.allOperations + [mergeOperation] + additionalInfoWrapper.allOperations + enactmentsWrapper.allOperations + [mergeOperation] return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift index a9ae457507..a8b679ef0b 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift @@ -3,7 +3,7 @@ import RobinHood import BigInt import SubstrateSdk -final class Gov1OperationFactory: GovernanceOperationFactory { +final class Gov1OperationFactory { static let trackName: String = "root" static let trackId: Referenda.TrackId = 0 @@ -14,39 +14,83 @@ final class Gov1OperationFactory: GovernanceOperationFactory { let block: BlockNumber } + struct SchedulerTaskName: Encodable { + let index: Referenda.ReferendumIndex + + func encode(to encoder: Encoder) throws { + let scaleEncoder = ScaleEncoder() + "democrac".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } + try index.encode(scaleEncoder: scaleEncoder) + + let data = scaleEncoder.encode() + + var container = encoder.singleValueContainer() + try container.encode(BytesCodable(wrappedValue: data)) + } + } + + let requestFactory: StorageRequestFactoryProtocol + let operationQueue: OperationQueue + + init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { + self.requestFactory = requestFactory + self.operationQueue = operationQueue + } + func createEnacmentTimeFetchWrapper( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: Democracy.ReferendumInfo]>, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockHash: Data? ) -> CompoundOperationWrapper<[ReferendumIdLocal: BlockNumber]> { - let approvedReferendumsOperation = ClosureOperation> { + let keysClosure: () throws -> [SchedulerTaskName] = { let referendums = try referendumOperation.extractNoCancellableResultData() - let items: [Referenda.ReferendumIndex] = referendums.compactMap { keyValue in + return referendums.compactMap { keyValue in switch keyValue.value { case let .finished(status): - return status.approved ? keyValue.key.referendumIndex : nil + if status.approved { + return SchedulerTaskName(index: keyValue.key.referendumIndex) + } else { + return nil + } default: return nil } } - - return Set(items) } - let fetchWrapper = createEnacmentTimeFetchWrapper( - dependingOn: approvedReferendumsOperation, - connection: connection, - runtimeProvider: runtimeProvider, - blockHash: blockHash - ) + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let enactmentWrapper: CompoundOperationWrapper<[StorageResponse]> = + requestFactory.queryItems( + engine: connection, + keyParams: keysClosure, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: OnChainScheduler.lookupTaskPath, + at: blockHash + ) + + enactmentWrapper.addDependency(operations: [codingFactoryOperation]) + + let mapOperation = ClosureOperation<[ReferendumIdLocal: BlockNumber]> { + let keys = try keysClosure() + let results = try enactmentWrapper.targetOperation.extractNoCancellableResultData() + + return zip(keys, results).reduce(into: [ReferendumIdLocal: BlockNumber]()) { accum, keyResult in + guard let when = keyResult.1.value?.when else { + return + } + + accum[ReferendumIdLocal(keyResult.0.index)] = when + } + } - fetchWrapper.addDependency(operations: [approvedReferendumsOperation]) + mapOperation.addDependency(enactmentWrapper.targetOperation) - let dependencies = [approvedReferendumsOperation] + fetchWrapper.dependencies + let dependencies = [codingFactoryOperation] + enactmentWrapper.allOperations - return CompoundOperationWrapper(targetOperation: fetchWrapper.targetOperation, dependencies: dependencies) + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } func createAdditionalInfoWrapper( @@ -116,12 +160,12 @@ final class Gov1OperationFactory: GovernanceOperationFactory { func createReferendumMapOperation( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: Democracy.ReferendumInfo]>, additionalInfoOperation: BaseOperation, - enactmentsOperation _: BaseOperation<[ReferendumIdLocal: BlockNumber]> - + enactmentsOperation: BaseOperation<[ReferendumIdLocal: BlockNumber]> ) -> BaseOperation<[ReferendumLocal]> { ClosureOperation<[ReferendumLocal]> { let remoteReferendums = try referendumOperation.extractNoCancellableResultData() let additionalInfo = try additionalInfoOperation.extractNoCancellableResultData() + let enacmentBlocks = try enactmentsOperation.extractNoCancellableResultData() let mappingFactory = Gov1LocalMappingFactory() @@ -132,7 +176,8 @@ final class Gov1OperationFactory: GovernanceOperationFactory { return mappingFactory.mapRemote( referendum: remoteReferendum, index: Referenda.ReferendumIndex(referendumIndex), - additionalInfo: additionalInfo + additionalInfo: additionalInfo, + enactmentBlock: enacmentBlocks[referendumIndex] ) } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2OperationFactory.swift index a992940c1a..ee56e89536 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov2OperationFactory.swift @@ -3,46 +3,87 @@ import SubstrateSdk import RobinHood import BigInt -final class Gov2OperationFactory: GovernanceOperationFactory { +final class Gov2OperationFactory { struct AdditionalInfo { let tracks: [Referenda.TrackId: Referenda.TrackInfo] let totalIssuance: BigUInt let undecidingTimeout: Moment } + struct SchedulerTaskName: Encodable { + let index: Referenda.ReferendumIndex + + func encode(to encoder: Encoder) throws { + let scaleEncoder = ScaleEncoder() + "assembly".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } + try "enactment".encode(scaleEncoder: scaleEncoder) + try index.encode(scaleEncoder: scaleEncoder) + + let data = try scaleEncoder.encode().blake2b32() + + var container = encoder.singleValueContainer() + try container.encode(BytesCodable(wrappedValue: data)) + } + } + + let requestFactory: StorageRequestFactoryProtocol + let operationQueue: OperationQueue + + init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { + self.requestFactory = requestFactory + self.operationQueue = operationQueue + } + func createEnacmentTimeFetchWrapper( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: ReferendumInfo]>, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockHash: Data? ) -> CompoundOperationWrapper<[ReferendumIdLocal: BlockNumber]> { - let approvedReferendumsOperation = ClosureOperation> { + let keysClosure: () throws -> [SchedulerTaskName] = { let referendums = try referendumOperation.extractNoCancellableResultData() - let items: [Referenda.ReferendumIndex] = referendums.compactMap { keyValue in + return referendums.compactMap { keyValue in switch keyValue.value { case .approved: - return keyValue.key.referendumIndex + return SchedulerTaskName(index: keyValue.key.referendumIndex) default: return nil } } - - return Set(items) } - let fetchWrapper = createEnacmentTimeFetchWrapper( - dependingOn: approvedReferendumsOperation, - connection: connection, - runtimeProvider: runtimeProvider, - blockHash: blockHash - ) + let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + + let enactmentWrapper: CompoundOperationWrapper<[StorageResponse]> = + requestFactory.queryItems( + engine: connection, + keyParams: keysClosure, + factory: { try codingFactoryOperation.extractNoCancellableResultData() }, + storagePath: OnChainScheduler.lookupTaskPath, + at: blockHash + ) + + enactmentWrapper.addDependency(operations: [codingFactoryOperation]) + + let mapOperation = ClosureOperation<[ReferendumIdLocal: BlockNumber]> { + let keys = try keysClosure() + let results = try enactmentWrapper.targetOperation.extractNoCancellableResultData() + + return zip(keys, results).reduce(into: [ReferendumIdLocal: BlockNumber]()) { accum, keyResult in + guard let when = keyResult.1.value?.when else { + return + } + + accum[ReferendumIdLocal(keyResult.0.index)] = when + } + } - fetchWrapper.addDependency(operations: [approvedReferendumsOperation]) + mapOperation.addDependency(enactmentWrapper.targetOperation) - let dependencies = [approvedReferendumsOperation] + fetchWrapper.dependencies + let dependencies = [codingFactoryOperation] + enactmentWrapper.allOperations - return CompoundOperationWrapper(targetOperation: fetchWrapper.targetOperation, dependencies: dependencies) + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) } func createReferendumMapOperation( diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/GovernanceOperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/GovernanceOperationFactory.swift deleted file mode 100644 index ac925c4942..0000000000 --- a/novawallet/Modules/Vote/Governance/Operation/Fetch/GovernanceOperationFactory.swift +++ /dev/null @@ -1,76 +0,0 @@ -import Foundation -import SubstrateSdk -import RobinHood - -class GovernanceOperationFactory { - struct SchedulerTaskName: Encodable { - let index: Referenda.ReferendumIndex - - func encode(to encoder: Encoder) throws { - let scaleEncoder = ScaleEncoder() - "assembly".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } - try "enactment".encode(scaleEncoder: scaleEncoder) - try index.encode(scaleEncoder: scaleEncoder) - - let data = try scaleEncoder.encode().blake2b32() - - var container = encoder.singleValueContainer() - try container.encode(BytesCodable(wrappedValue: data)) - } - } - - let requestFactory: StorageRequestFactoryProtocol - let operationQueue: OperationQueue - - init(requestFactory: StorageRequestFactoryProtocol, operationQueue: OperationQueue) { - self.requestFactory = requestFactory - self.operationQueue = operationQueue - } - - func createEnacmentTimeFetchWrapper( - dependingOn referendumOperation: BaseOperation>, - connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol, - blockHash: Data? - ) -> CompoundOperationWrapper<[ReferendumIdLocal: BlockNumber]> { - let keysClosure: () throws -> [SchedulerTaskName] = { - let referendums = try referendumOperation.extractNoCancellableResultData() - - return Array(referendums).map { key in - SchedulerTaskName(index: key) - } - } - - let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - - let enactmentWrapper: CompoundOperationWrapper<[StorageResponse]> = - requestFactory.queryItems( - engine: connection, - keyParams: keysClosure, - factory: { try codingFactoryOperation.extractNoCancellableResultData() }, - storagePath: OnChainScheduler.lookupTaskPath, - at: blockHash - ) - - enactmentWrapper.addDependency(operations: [codingFactoryOperation]) - - let mapOperation = ClosureOperation<[ReferendumIdLocal: BlockNumber]> { - let keys = try keysClosure() - let results = try enactmentWrapper.targetOperation.extractNoCancellableResultData() - - return zip(keys, results).reduce(into: [ReferendumIdLocal: BlockNumber]()) { accum, keyResult in - guard let when = keyResult.1.value?.when else { - return - } - - accum[ReferendumIdLocal(keyResult.0.index)] = when - } - } - - mapOperation.addDependency(enactmentWrapper.targetOperation) - - let dependencies = [codingFactoryOperation] + enactmentWrapper.allOperations - - return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) - } -} From e4d065c22f0a3dde97972f5fbd1ba4f75f63db78 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 18:13:37 +0500 Subject: [PATCH 192/229] actualize version --- Podfile | 2 +- Podfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Podfile b/Podfile index cea58c89cb..e71ea5ec3a 100644 --- a/Podfile +++ b/Podfile @@ -22,7 +22,7 @@ abstract_target 'novawalletAll' do pod 'Charts' pod 'SwiftRLP', :git => 'https://github.com/ERussel/SwiftRLP.git' pod 'Starscream', :git => 'https://github.com/ERussel/Starscream.git', :tag => '4.0.5' - pod 'CDMarkdownKit', :git => 'https://github.com/nova-wallet/CDMarkdownKit.git', :commit => '2983924e34461646b6bd770a16ab6f6603fc4b24' + pod 'CDMarkdownKit', :git => 'https://github.com/nova-wallet/CDMarkdownKit.git', :tag => '2.4.0' target 'novawalletTests' do inherit! :search_paths diff --git a/Podfile.lock b/Podfile.lock index 5bfa39913c..1a436d7332 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -126,7 +126,7 @@ PODS: - xxHash-Swift (1.0.13) DEPENDENCIES: - - CDMarkdownKit (from `https://github.com/nova-wallet/CDMarkdownKit.git`, commit `2983924e34461646b6bd770a16ab6f6603fc4b24`) + - CDMarkdownKit (from `https://github.com/nova-wallet/CDMarkdownKit.git`, tag `2.4.0`) - Charts - CommonWallet/Core (from `https://github.com/ERussel/Capital-iOS.git`, tag `1.16.0`) - Cuckoo @@ -177,8 +177,8 @@ SPEC REPOS: EXTERNAL SOURCES: CDMarkdownKit: - :commit: 2983924e34461646b6bd770a16ab6f6603fc4b24 :git: https://github.com/nova-wallet/CDMarkdownKit.git + :tag: 2.4.0 CommonWallet: :git: https://github.com/ERussel/Capital-iOS.git :tag: 1.16.0 @@ -199,8 +199,8 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: CDMarkdownKit: - :commit: 2983924e34461646b6bd770a16ab6f6603fc4b24 :git: https://github.com/nova-wallet/CDMarkdownKit.git + :tag: 2.4.0 CommonWallet: :git: https://github.com/ERussel/Capital-iOS.git :tag: 1.16.0 @@ -253,6 +253,6 @@ SPEC CHECKSUMS: TweetNacl: 3abf4d1d2082b0114e7a67410e300892448951e6 xxHash-Swift: 30bd6a7507b3b7348a277c49b1cb6346c2905ec7 -PODFILE CHECKSUM: ebaedd559bf22ed6a7f0f6ad82c2fb6f5342e172 +PODFILE CHECKSUM: f0266fabfe6e7f6dfb62690262b3b1c8ab02bfba COCOAPODS: 1.11.3 From 3c94222522885a40fac773111fc15e89154f0b50 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 22:34:04 +0500 Subject: [PATCH 193/229] invalidate unlock schedule on network switch --- .../Vote/Governance/Referendums/ReferendumsPresenter.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 59fbcbbded..0dd81f8c41 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -62,6 +62,7 @@ final class ReferendumsPresenter { referendums = nil referendumsMetadata = nil voting = nil + unlockSchedule = nil blockNumber = nil blockTime = nil maxStatusTimeInterval = nil From 09bc0a6d7db71a6c4bad663e2da8964600fe85d8 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 22:58:59 +0500 Subject: [PATCH 194/229] add blocktime service --- .../Model/GovernanceSharedState.swift | 8 ++++++ .../Referendums/ReferendumsInteractor.swift | 26 ++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index 38634220f1..d99016d8e4 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -152,4 +152,12 @@ final class GovernanceSharedState { return nil } } + + func createBlockTimeOperationFactory() -> BlockTimeOperationFactoryProtocol? { + guard let chain = settings.value else { + return nil + } + + return BlockTimeOperationFactory(chain: chain) + } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index fac2a37a23..304ca05123 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -185,22 +185,34 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani } private func provideBlockTime() { - guard blockTimeCancellable == nil, let blockTimeService = governanceState.blockTimeService else { + guard + blockTimeCancellable == nil, + let blockTimeService = governanceState.blockTimeService, + let blockTimeFactory = governanceState.createBlockTimeOperationFactory(), + let chain = governanceState.settings.value else { return } - let blockTimeOperation = blockTimeService.createEstimatedBlockTimeOperation() + guard let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId) else { + presenter?.didReceiveError(.blockTimeFetchFailed(ChainRegistryError.runtimeMetadaUnavailable)) + return + } + + let blockTimeWrapper = blockTimeFactory.createBlockTimeOperation( + from: runtimeProvider, + blockTimeEstimationService: blockTimeService + ) - blockTimeOperation.completionBlock = { [weak self] in + blockTimeWrapper.targetOperation.completionBlock = { [weak self] in DispatchQueue.main.async { - guard self?.blockTimeCancellable === blockTimeOperation else { + guard self?.blockTimeCancellable === blockTimeWrapper else { return } self?.blockTimeCancellable = nil do { - let blockTime = try blockTimeOperation.extractNoCancellableResultData().blockTime + let blockTime = try blockTimeWrapper.targetOperation.extractNoCancellableResultData() self?.presenter?.didReceiveBlockTime(blockTime) } catch { @@ -209,9 +221,9 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani } } - blockTimeCancellable = blockTimeOperation + blockTimeCancellable = blockTimeWrapper - operationQueue.addOperation(blockTimeOperation) + operationQueue.addOperations(blockTimeWrapper.allOperations, waitUntilFinished: false) } private func provideReferendumsIfNeeded() { From b65165b9b141f36926f2bcd5a9933180c7aff202 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 23:19:48 +0500 Subject: [PATCH 195/229] proper blocktime estimation --- .../GovernanceUnlockInteractor.swift | 20 ++++++++++++------- .../GovernanceUnlockConfirmInteractor.swift | 2 ++ .../GovernanceUnlockConfirmViewFactory.swift | 2 ++ .../GovernanceUnlockSetupViewFactory.swift | 4 +++- .../ReferendumDetailsInteractor.swift | 20 ++++++++++++------- .../ReferendumDetailsViewFactory.swift | 2 ++ .../ReferendumVoteInteractor.swift | 20 ++++++++++++------- .../ReferendumVoteConfirmInteractor.swift | 2 ++ .../ReferendumVoteConfirmViewFactory.swift | 4 +++- .../ReferendumVoteSetupViewFactory.swift | 4 +++- 10 files changed, 56 insertions(+), 24 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift index 62d6195007..1475792e96 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlock/GovernanceUnlockInteractor.swift @@ -12,6 +12,7 @@ class GovernanceUnlockInteractor: GovernanceUnlockInteractorInputProtocol, AnyCa let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol let blockTimeService: BlockTimeEstimationServiceProtocol + let blockTimeFactory: BlockTimeOperationFactoryProtocol let connection: JSONRPCEngine let runtimeProvider: RuntimeProviderProtocol let operationQueue: OperationQueue @@ -30,6 +31,7 @@ class GovernanceUnlockInteractor: GovernanceUnlockInteractorInputProtocol, AnyCa priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, blockTimeService: BlockTimeEstimationServiceProtocol, + blockTimeFactory: BlockTimeOperationFactoryProtocol, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, operationQueue: OperationQueue, @@ -42,6 +44,7 @@ class GovernanceUnlockInteractor: GovernanceUnlockInteractorInputProtocol, AnyCa self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory self.blockTimeService = blockTimeService + self.blockTimeFactory = blockTimeFactory self.connection = connection self.runtimeProvider = runtimeProvider self.operationQueue = operationQueue @@ -63,28 +66,31 @@ class GovernanceUnlockInteractor: GovernanceUnlockInteractorInputProtocol, AnyCa return } - let operation = blockTimeService.createEstimatedBlockTimeOperation() + let wrapper = blockTimeFactory.createBlockTimeOperation( + from: runtimeProvider, + blockTimeEstimationService: blockTimeService + ) - operation.completionBlock = { [weak self] in + wrapper.targetOperation.completionBlock = { [weak self] in DispatchQueue.main.async { - guard operation === self?.blockTimeCancellable else { + guard wrapper === self?.blockTimeCancellable else { return } self?.blockTimeCancellable = nil do { - let blockTimeModel = try operation.extractNoCancellableResultData() - self?.basePresenter?.didReceiveBlockTime(blockTimeModel.blockTime) + let blockTimeModel = try wrapper.targetOperation.extractNoCancellableResultData() + self?.basePresenter?.didReceiveBlockTime(blockTimeModel) } catch { self?.basePresenter?.didReceiveBaseError(.blockTimeFetchFailed(error)) } } } - blockTimeCancellable = operation + blockTimeCancellable = wrapper - operationQueue.addOperation(operation) + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } func provideUnlockSchedule(for tracksVoting: ReferendumTracksVotingDistribution, blockHash: Data?) { diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift index f883398d1d..91f53ef412 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmInteractor.swift @@ -34,6 +34,7 @@ final class GovernanceUnlockConfirmInteractor: GovernanceUnlockInteractor, AnyPr priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, blockTimeService: BlockTimeEstimationServiceProtocol, + blockTimeFactory: BlockTimeOperationFactoryProtocol, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, operationQueue: OperationQueue, @@ -52,6 +53,7 @@ final class GovernanceUnlockConfirmInteractor: GovernanceUnlockInteractor, AnyPr priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, generalLocalSubscriptionFactory: generalLocalSubscriptionFactory, blockTimeService: blockTimeService, + blockTimeFactory: blockTimeFactory, connection: connection, runtimeProvider: runtimeProvider, operationQueue: operationQueue, diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift index 37a3628271..bfa9103a99 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift @@ -80,6 +80,7 @@ struct GovernanceUnlockConfirmViewFactory { let lockStateFactory = state.locksOperationFactory, let extrinsicFactory = state.createExtrinsicFactory(for: chain), let blockTimeService = state.blockTimeService, + let blockTimeFactory = state.createBlockTimeOperationFactory(), let currencyManager = CurrencyManager.shared else { return nil } @@ -109,6 +110,7 @@ struct GovernanceUnlockConfirmViewFactory { priceLocalSubscriptionFactory: PriceProviderFactory.shared, generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, blockTimeService: blockTimeService, + blockTimeFactory: blockTimeFactory, connection: connection, runtimeProvider: runtimeProvider, operationQueue: operationQueue, diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift index 5f7c3b009f..da93796e20 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift @@ -50,7 +50,8 @@ struct GovernanceUnlockSetupViewFactory { let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId), let subscriptionFactory = state.subscriptionFactory, let lockStateFactory = state.locksOperationFactory, - let blockTimeService = state.blockTimeService else { + let blockTimeService = state.blockTimeService, + let blockTimeFactory = state.createBlockTimeOperationFactory() else { return nil } @@ -62,6 +63,7 @@ struct GovernanceUnlockSetupViewFactory { priceLocalSubscriptionFactory: PriceProviderFactory.shared, generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, blockTimeService: blockTimeService, + blockTimeFactory: blockTimeFactory, connection: connection, runtimeProvider: runtimeProvider, operationQueue: OperationManagerFacade.sharedDefaultQueue, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index e7fac9b7a2..8d9f971878 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -15,6 +15,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { let runtimeProvider: RuntimeProviderProtocol let identityOperationFactory: IdentityOperationFactoryProtocol let blockTimeService: BlockTimeEstimationServiceProtocol + let blockTimeFactory: BlockTimeOperationFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol let referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol @@ -39,6 +40,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, blockTimeService: BlockTimeEstimationServiceProtocol, + blockTimeFactory: BlockTimeOperationFactoryProtocol, identityOperationFactory: IdentityOperationFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol, @@ -58,6 +60,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory self.blockTimeService = blockTimeService + self.blockTimeFactory = blockTimeFactory self.govMetadataLocalSubscriptionFactory = govMetadataLocalSubscriptionFactory self.referendumsSubscriptionFactory = referendumsSubscriptionFactory self.dAppsProvider = dAppsProvider @@ -202,28 +205,31 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { return } - let operation = blockTimeService.createEstimatedBlockTimeOperation() + let wrapper = blockTimeFactory.createBlockTimeOperation( + from: runtimeProvider, + blockTimeEstimationService: blockTimeService + ) - operation.completionBlock = { [weak self] in + wrapper.targetOperation.completionBlock = { [weak self] in DispatchQueue.main.async { - guard operation === self?.blockTimeCancellable else { + guard wrapper === self?.blockTimeCancellable else { return } self?.blockTimeCancellable = nil do { - let blockTimeModel = try operation.extractNoCancellableResultData() - self?.presenter?.didReceiveBlockTime(blockTimeModel.blockTime) + let blockTimeModel = try wrapper.targetOperation.extractNoCancellableResultData() + self?.presenter?.didReceiveBlockTime(blockTimeModel) } catch { self?.presenter?.didReceiveError(.blockTimeFailed(error)) } } } - blockTimeCancellable = operation + blockTimeCancellable = wrapper - operationQueue.addOperation(operation) + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } private func updateActionDetails() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index f11258b90d..aad80823a5 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -101,6 +101,7 @@ struct ReferendumDetailsViewFactory { let connection = chainRegistry.getConnection(for: chain.chainId), let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId), let blockTimeService = state.blockTimeService, + let blockTimeFactory = state.createBlockTimeOperationFactory(), let subscriptionFactory = state.subscriptionFactory, let actionDetailsFactory = state.createActionsDetailsFactory(for: chain) else { return nil @@ -129,6 +130,7 @@ struct ReferendumDetailsViewFactory { connection: connection, runtimeProvider: runtimeProvider, blockTimeService: blockTimeService, + blockTimeFactory: blockTimeFactory, identityOperationFactory: identityOperationFactory, priceLocalSubscriptionFactory: PriceProviderFactory.shared, generalLocalSubscriptionFactory: state.generalLocalSubscriptionFactory, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift index 5d17390785..df422392c4 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVote/ReferendumVoteInteractor.swift @@ -17,6 +17,7 @@ class ReferendumVoteInteractor: AnyCancellableCleaning { let extrinsicFactory: GovernanceExtrinsicFactoryProtocol let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol let blockTimeService: BlockTimeEstimationServiceProtocol + let blockTimeFactory: BlockTimeOperationFactoryProtocol let lockStateFactory: GovernanceLockStateFactoryProtocol let connection: JSONRPCEngine let runtimeProvider: RuntimeProviderProtocol @@ -38,6 +39,7 @@ class ReferendumVoteInteractor: AnyCancellableCleaning { walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, blockTimeService: BlockTimeEstimationServiceProtocol, + blockTimeFactory: BlockTimeOperationFactoryProtocol, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, currencyManager: CurrencyManagerProtocol, @@ -52,6 +54,7 @@ class ReferendumVoteInteractor: AnyCancellableCleaning { self.chain = chain self.generalLocalSubscriptionFactory = generalLocalSubscriptionFactory self.blockTimeService = blockTimeService + self.blockTimeFactory = blockTimeFactory self.connection = connection self.runtimeProvider = runtimeProvider self.referendumsSubscriptionFactory = referendumsSubscriptionFactory @@ -89,28 +92,31 @@ class ReferendumVoteInteractor: AnyCancellableCleaning { return } - let operation = blockTimeService.createEstimatedBlockTimeOperation() + let wrapper = blockTimeFactory.createBlockTimeOperation( + from: runtimeProvider, + blockTimeEstimationService: blockTimeService + ) - operation.completionBlock = { [weak self] in + wrapper.targetOperation.completionBlock = { [weak self] in DispatchQueue.main.async { - guard operation === self?.blockTimeCancellable else { + guard wrapper === self?.blockTimeCancellable else { return } self?.blockTimeCancellable = nil do { - let blockTimeModel = try operation.extractNoCancellableResultData() - self?.basePresenter?.didReceiveBlockTime(blockTimeModel.blockTime) + let blockTimeModel = try wrapper.targetOperation.extractNoCancellableResultData() + self?.basePresenter?.didReceiveBlockTime(blockTimeModel) } catch { self?.basePresenter?.didReceiveBaseError(.blockTimeFailed(error)) } } } - blockTimeCancellable = operation + blockTimeCancellable = wrapper - operationQueue.addOperation(operation) + operationQueue.addOperations(wrapper.allOperations, waitUntilFinished: false) } private func subscribeAccountVotes() { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift index 6a09626623..50663fb24f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmInteractor.swift @@ -26,6 +26,7 @@ final class ReferendumVoteConfirmInteractor: ReferendumVoteInteractor { walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, blockTimeService: BlockTimeEstimationServiceProtocol, + blockTimeFactory: BlockTimeOperationFactoryProtocol, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, currencyManager: CurrencyManagerProtocol, @@ -47,6 +48,7 @@ final class ReferendumVoteConfirmInteractor: ReferendumVoteInteractor { walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, blockTimeService: blockTimeService, + blockTimeFactory: blockTimeFactory, connection: connection, runtimeProvider: runtimeProvider, currencyManager: currencyManager, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift index d5e616793c..aebc568a2e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -88,7 +88,8 @@ struct ReferendumVoteConfirmViewFactory { let subscriptionFactory = state.subscriptionFactory, let lockStateFactory = state.locksOperationFactory, let extrinsicFactory = state.createExtrinsicFactory(for: chain), - let blockTimeService = state.blockTimeService + let blockTimeService = state.blockTimeService, + let blockTimeFactory = state.createBlockTimeOperationFactory() else { return nil } @@ -122,6 +123,7 @@ struct ReferendumVoteConfirmViewFactory { walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, priceLocalSubscriptionFactory: PriceProviderFactory.shared, blockTimeService: blockTimeService, + blockTimeFactory: blockTimeFactory, connection: connection, runtimeProvider: runtimeProvider, currencyManager: currencyManager, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index 1e4eb5ca72..521c7ded9a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -109,7 +109,8 @@ struct ReferendumVoteSetupViewFactory { let subscriptionFactory = state.subscriptionFactory, let lockStateFactory = state.locksOperationFactory, let extrinsicFactory = state.createExtrinsicFactory(for: chain), - let blockTimeService = state.blockTimeService + let blockTimeService = state.blockTimeService, + let blockTimeFactory = state.createBlockTimeOperationFactory() else { return nil } @@ -138,6 +139,7 @@ struct ReferendumVoteSetupViewFactory { walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, priceLocalSubscriptionFactory: PriceProviderFactory.shared, blockTimeService: blockTimeService, + blockTimeFactory: blockTimeFactory, connection: connection, runtimeProvider: runtimeProvider, currencyManager: currencyManager, From 635b91c1e465da6fc3a8d128a64a9067bf4530e0 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 23:28:55 +0500 Subject: [PATCH 196/229] fix parachain staking redeem --- .../Parachain/ParaStkRedeem/ParaStkRedeemViewFactory.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/novawallet/Modules/Staking/Parachain/ParaStkRedeem/ParaStkRedeemViewFactory.swift b/novawallet/Modules/Staking/Parachain/ParaStkRedeem/ParaStkRedeemViewFactory.swift index c4cb09e7ea..0881029542 100644 --- a/novawallet/Modules/Staking/Parachain/ParaStkRedeem/ParaStkRedeemViewFactory.swift +++ b/novawallet/Modules/Staking/Parachain/ParaStkRedeem/ParaStkRedeemViewFactory.swift @@ -47,6 +47,7 @@ struct ParaStkRedeemViewFactory { presenter.view = view interactor.presenter = presenter + dataValidationFactory.view = view return view } From ab8f6e952ca9b20ccfe5328a66a710254a72c327 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 23:32:51 +0500 Subject: [PATCH 197/229] fix voters title --- novawallet/en.lproj/Localizable.strings | 4 ++-- novawallet/ru.lproj/Localizable.strings | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 7b85a9402f..5a33ad7758 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1021,8 +1021,8 @@ "gov.track.big.spender" = "Treasury: Big Spend"; "gov.track.whitelisted.caller" = "Fellowship: Whitelist"; "gov.track.fellowship.admin" = "Fellowship: Admin"; -"gov.voters.aye" = "Aye voters"; -"gov.voters.nay" = "Nay voters"; +"gov.voters.aye" = "Aye votes"; +"gov.voters.nay" = "Nay votes"; "gov.common.votes.format" = "%@ votes"; "gov.common.amount.conviction.format" = "%@ × %@x"; "gov.voters.empty" = "List of voters will appear here"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 88ca4f6298..214ef7c9eb 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1022,8 +1022,8 @@ "gov.track.big.spender" = "Treasury: Big Spend"; "gov.track.whitelisted.caller" = "Fellowship: Whitelist"; "gov.track.fellowship.admin" = "Fellowship: Admin"; -"gov.voters.aye" = "За голосовали"; -"gov.voters.nay" = "Против голосовали"; +"gov.voters.aye" = "Голоса за"; +"gov.voters.nay" = "Голоса против"; "gov.common.votes.format" = "%@ голосов"; "gov.common.amount.conviction.format" = "%@ × %@x"; "gov.voters.empty" = "Список проголосовавших появится здесь"; From bb1a774fa500309cb4a8c783f9820a24c6db000c Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 23:34:26 +0500 Subject: [PATCH 198/229] fix sender on confirm --- .../GovernanceUnlockConfirmViewController.swift | 2 +- .../ReferendumVoteConfirmViewController.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift index 3b653b65f3..fbd4342384 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewController.swift @@ -53,7 +53,7 @@ final class GovernanceUnlockConfirmViewController: UIViewController, ViewHolder, preferredLanguages: languages ) - rootView.accountCell.titleLabel.text = R.string.localizable.commonSender( + rootView.accountCell.titleLabel.text = R.string.localizable.commonAccount( preferredLanguages: languages ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift index da7a62db16..6d3ddb5436 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewController.swift @@ -53,7 +53,7 @@ final class ReferendumVoteConfirmViewController: UIViewController, ViewHolder { applyReferendumNumber() rootView.walletCell.titleLabel.text = R.string.localizable.commonWallet(preferredLanguages: languages) - rootView.accountCell.titleLabel.text = R.string.localizable.commonSender(preferredLanguages: languages) + rootView.accountCell.titleLabel.text = R.string.localizable.commonAccount(preferredLanguages: languages) rootView.feeCell.rowContentView.locale = selectedLocale From 8a3126943027963e1a2cbf9986dd8017f231fc33 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 23:46:22 +0500 Subject: [PATCH 199/229] show only other locks in unlock confirm --- .../GovernanceUnlockConfirmPresenter.swift | 7 ++----- ...ReferendumLockChangeViewModelFactory.swift | 19 +++---------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift index 45f0d1f6d4..4383549844 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift @@ -141,11 +141,8 @@ final class GovernanceUnlockConfirmPresenter { view?.didReceiveTransferableAmount(viewModel: transferableViewModel) } - if let locks = locks, let chainAssetId = chain.utilityChainAssetId() { - let remainedLocksViewModel = lockChangeViewModelFactory.createRemainedLockViewModel( - after: remainedLocked, - chainAssetId: chainAssetId, - accountId: selectedAccount.chainAccount.accountId, + if let locks = locks { + let remainedLocksViewModel = lockChangeViewModelFactory.createRemainedOtherLocksViewModel( locks: locks, locale: selectedLocale ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift index 87c1b61dbe..871a0d6aaa 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift @@ -24,10 +24,7 @@ protocol ReferendumLockChangeViewModelFactoryProtocol { locale: Locale ) -> ReferendumLockTransitionViewModel? - func createRemainedLockViewModel( - after remainedGovernanceLock: BigUInt, - chainAssetId: ChainAssetId, - accountId: AccountId, + func createRemainedOtherLocksViewModel( locks: AssetLocks, locale: Locale ) -> GovernanceRemainedLockViewModel? @@ -102,23 +99,13 @@ final class ReferendumLockChangeViewModelFactory { } extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol { - func createRemainedLockViewModel( - after remainedGovernanceLock: BigUInt, - chainAssetId: ChainAssetId, - accountId: AccountId, + func createRemainedOtherLocksViewModel( locks: AssetLocks, locale: Locale ) -> GovernanceRemainedLockViewModel? { let otherLocks = locks.filter { $0.displayId != votingLockId } - let newLock = AssetLock( - chainAssetId: chainAssetId, - accountId: accountId, - type: votingLockId.data(using: .utf8) ?? Data(), - amount: remainedGovernanceLock - ) - - let newLocks = (otherLocks + [newLock]).sorted { $0.amount > $1.amount } + let newLocks = otherLocks.sorted { $0.amount > $1.amount } if let lockedAmount = newLocks.first?.amount, lockedAmount > 0 { let amountDecimal = Decimal.fromSubstrateAmount( From c880e4d77f5c40570f057706a601b50f28d98316 Mon Sep 17 00:00:00 2001 From: ERussel Date: Fri, 11 Nov 2022 23:47:47 +0500 Subject: [PATCH 200/229] hide dapp section when empty --- .../ReferendumDetails/ReferendumDetailsViewLayout.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift index b79f7c8f78..23c496480d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewLayout.swift @@ -68,7 +68,7 @@ final class ReferendumDetailsViewLayout: UIView { func setDApps(models: [ReferendumDAppView.Model]?, locale: Locale) -> [ReferendumDAppCellView] { dAppsTableView.clear() - if let models = models { + if let models = models, !models.isEmpty { dAppsTableView.isHidden = false let title = R.string.localizable.commonUseDapp( From 29d443e6c875d60a1183dd2f441a387619bbfe0a Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 10:52:25 +0500 Subject: [PATCH 201/229] add proposer to referendum full details and fixes --- .../ReferendumDetails/ReferendumDetailsPresenter.swift | 1 + .../ReferendumDetails/ReferendumDetailsProtocols.swift | 1 + .../ReferendumDetails/ReferendumDetailsWireframe.swift | 2 ++ .../ReferendumFullDetailsPresenter.swift | 6 +++++- .../ReferendumFullDetailsViewFactory.swift | 2 ++ .../ReferendumFullDetailsViewLayout.swift | 2 +- 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 5e544c1441..ca35c4b054 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -433,6 +433,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { from: view, referendum: referendum, actionDetails: actionDetails, + metadata: referendumMetadata, identities: identities ?? [:] ) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 6eca01a943..214a771682 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -52,6 +52,7 @@ protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal, actionDetails: ReferendumActionLocal, + metadata: ReferendumMetadataLocal?, identities: [AccountAddress: AccountIdentity] ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index b826e4c1f0..64dceb1986 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -11,6 +11,7 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal, actionDetails: ReferendumActionLocal, + metadata: ReferendumMetadataLocal?, identities: [AccountAddress: AccountIdentity] ) { guard @@ -18,6 +19,7 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { state: state, referendum: referendum, actionDetails: actionDetails, + metadata: metadata, identities: identities ) else { return diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index a22ad980f6..1d3f7bbf72 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -14,6 +14,7 @@ final class ReferendumFullDetailsPresenter { let chain: ChainModel let referendum: ReferendumLocal let actionDetails: ReferendumActionLocal + let metadata: ReferendumMetadataLocal? let identities: [AccountAddress: AccountIdentity] private var price: PriceData? @@ -25,6 +26,7 @@ final class ReferendumFullDetailsPresenter { chain: ChainModel, referendum: ReferendumLocal, actionDetails: ReferendumActionLocal, + metadata: ReferendumMetadataLocal?, identities: [AccountAddress: AccountIdentity], balanceViewModelFactory: BalanceViewModelFactoryProtocol, addressViewModelFactory: DisplayAddressViewModelFactoryProtocol, @@ -35,6 +37,7 @@ final class ReferendumFullDetailsPresenter { self.wireframe = wireframe self.chain = chain self.referendum = referendum + self.metadata = metadata self.actionDetails = actionDetails self.identities = identities self.logger = logger @@ -72,7 +75,8 @@ final class ReferendumFullDetailsPresenter { } private func provideProposerViewModel() { - guard let proposer = getAccountViewModel(referendum.proposer) else { + let optProposerId = referendum.proposer ?? metadata?.proposerAccountId(for: chain.chainFormat) + guard let proposer = getAccountViewModel(optProposerId) else { view?.didReceive(proposer: nil) return } diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift index 64b2c90c38..b614b9d71a 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift @@ -7,6 +7,7 @@ struct ReferendumFullDetailsViewFactory { state: GovernanceSharedState, referendum: ReferendumLocal, actionDetails: ReferendumActionLocal, + metadata: ReferendumMetadataLocal?, identities: [AccountAddress: AccountIdentity] ) -> ReferendumFullDetailsViewProtocol? { guard @@ -41,6 +42,7 @@ struct ReferendumFullDetailsViewFactory { chain: chain, referendum: referendum, actionDetails: actionDetails, + metadata: metadata, identities: identities, balanceViewModelFactory: balanceViewModelFactory, addressViewModelFactory: DisplayAddressViewModelFactory(), diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index 6c4578849f..2cad51c418 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -111,7 +111,7 @@ final class ReferendumFullDetailsViewLayout: UIView { func setVoting(viewModel: ReferendumFullDetailsViewModel.Voting?, locale: Locale) { curveAndHashTableView?.clear() - curveAndHashTableView = nil + callHashCell = nil if let viewModel = viewModel { if curveAndHashTableView == nil { From f0ab405881ec2c0e4470b521cf87de29ed9334dc Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 12:40:30 +0500 Subject: [PATCH 202/229] provide init data for voting flow to address empty fields --- novawallet.xcodeproj/project.pbxproj | 8 +++ .../Model/ReferendumDetailsInitData.swift | 13 ++++ .../ReferendumDetailsInteractor.swift | 7 +- .../ReferendumDetailsPresenter.swift | 30 ++++++--- .../ReferendumDetailsProtocols.swift | 11 +++- .../ReferendumDetailsViewFactory.swift | 65 ++++++++++++------- .../ReferendumDetailsWireframe.swift | 9 ++- .../ReferendumVoteConfirmPresenter.swift | 6 ++ .../ReferendumVoteConfirmViewFactory.swift | 4 +- .../Model/ReferendumVotingInitData.swift | 9 +++ .../ReferendumVoteSetupPresenter.swift | 16 ++++- .../ReferendumVoteSetupProtocols.swift | 6 +- .../ReferendumVoteSetupViewFactory.swift | 6 +- .../ReferendumVoteSetupWireframe.swift | 9 ++- .../Referendums/ReferendumsPresenter.swift | 11 ++-- .../Referendums/ReferendumsProtocols.swift | 7 +- .../Referendums/ReferendumsWireframe.swift | 11 +--- 17 files changed, 164 insertions(+), 64 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInitData.swift create mode 100644 novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumVotingInitData.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 09a582fb12..323fb7cf99 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1226,6 +1226,8 @@ 8476D39D27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D39C27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift */; }; 8476D39F27F4582A004D9A7A /* DAppMetamaskPhishingDetectedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D39E27F4582A004D9A7A /* DAppMetamaskPhishingDetectedState.swift */; }; 8476D3A127F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D3A027F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift */; }; + 84770F25291F72D700852A33 /* ReferendumVotingInitData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84770F24291F72D700852A33 /* ReferendumVotingInitData.swift */; }; + 84770F27291F7CD400852A33 /* ReferendumDetailsInitData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84770F26291F7CD400852A33 /* ReferendumDetailsInitData.swift */; }; 8477DAA32888329800129B45 /* watchOnlyPreset.json in Resources */ = {isa = PBXBuildFile; fileRef = 8477DAA22888329800129B45 /* watchOnlyPreset.json */; }; 8477DAA6288832CB00129B45 /* WatchOnlyPresetRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8477DAA5288832CB00129B45 /* WatchOnlyPresetRepository.swift */; }; 84786DA825F9F58E0089DFF7 /* EraValidatorService+Fetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84786DA725F9F58E0089DFF7 /* EraValidatorService+Fetch.swift */; }; @@ -4215,6 +4217,8 @@ 8476D39C27F44E73004D9A7A /* PhishingSiteVerifier+Init.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PhishingSiteVerifier+Init.swift"; sourceTree = ""; }; 8476D39E27F4582A004D9A7A /* DAppMetamaskPhishingDetectedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppMetamaskPhishingDetectedState.swift; sourceTree = ""; }; 8476D3A027F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserPhishingDetectedState.swift; sourceTree = ""; }; + 84770F24291F72D700852A33 /* ReferendumVotingInitData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotingInitData.swift; sourceTree = ""; }; + 84770F26291F7CD400852A33 /* ReferendumDetailsInitData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsInitData.swift; sourceTree = ""; }; 8477DAA22888329800129B45 /* watchOnlyPreset.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = watchOnlyPreset.json; sourceTree = ""; }; 8477DAA5288832CB00129B45 /* WatchOnlyPresetRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchOnlyPresetRepository.swift; sourceTree = ""; }; 84786DA725F9F58E0089DFF7 /* EraValidatorService+Fetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EraValidatorService+Fetch.swift"; sourceTree = ""; }; @@ -7113,6 +7117,7 @@ children = ( 8425D0DF28FE738D003B782A /* ReferendumVoteSetupInteractorError.swift */, 84F1D66C29051F240050F4E3 /* ReferendumReuseLockModel.swift */, + 84770F24291F72D700852A33 /* ReferendumVotingInitData.swift */, ); path = Model; sourceTree = ""; @@ -8600,6 +8605,7 @@ isa = PBXGroup; children = ( 8469D5A728F683930074FEE3 /* ReferendumDetailsInteractorError.swift */, + 84770F26291F7CD400852A33 /* ReferendumDetailsInitData.swift */, ); path = Model; sourceTree = ""; @@ -16630,6 +16636,7 @@ 19A29027666EB5388CBFAD61 /* StakingRewardDetailsInteractor.swift in Sources */, 846AC7EF2638D9200075F7DA /* YourValidatorTableCell.swift in Sources */, C937154FA9021AECD72A871B /* StakingRewardDetailsViewController.swift in Sources */, + 84770F27291F7CD400852A33 /* ReferendumDetailsInitData.swift in Sources */, 84E493252731C064000534F2 /* AssetListViewModel.swift in Sources */, AEA0C8B8267C905500F9666F /* SelectedValidatorCell.swift in Sources */, 8422F2EE2887E3D300C7B840 /* TextInputView.swift in Sources */, @@ -17205,6 +17212,7 @@ 6BBD025775841F8B055CA367 /* AssetsSearchViewFactory.swift in Sources */, 5188FF070CD05F92C93A5055 /* CreateWatchOnlyProtocols.swift in Sources */, 97BF7157FE13F723BF4D5713 /* CreateWatchOnlyWireframe.swift in Sources */, + 84770F25291F72D700852A33 /* ReferendumVotingInitData.swift in Sources */, 846A835D28B8D09600D92892 /* LedgerMessageSheetViewFactory.swift in Sources */, 60FFEE5B386E82D70333BE80 /* CreateWatchOnlyPresenter.swift in Sources */, 454D41CC5C7CC2FDAB778026 /* CreateWatchOnlyInteractor.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInitData.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInitData.swift new file mode 100644 index 0000000000..a4ce738202 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/Model/ReferendumDetailsInitData.swift @@ -0,0 +1,13 @@ +import Foundation + +struct ReferendumDetailsInitData { + let referendum: ReferendumLocal + let votesResult: CallbackStorageSubscriptionResult? + let blockNumber: BlockNumber? + let blockTime: BlockTime? + let metadata: ReferendumMetadataLocal? + + var accountVotes: ReferendumAccountVoteLocal? { + votesResult?.value?.votes.votes[referendum.index] + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 8d9f971878..0c502db406 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -104,7 +104,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { private func subscribeAccountVotes() { guard let accountId = selectedAccount?.accountId else { - presenter?.didReceiveAccountVotes(nil) + presenter?.didReceiveAccountVotes(nil, votingDistribution: nil) return } @@ -117,7 +117,10 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { switch result { case let .success(votesResult): if let votes = votesResult.value?.votes.votes, let referendumId = self?.referendum.index { - self?.presenter?.didReceiveAccountVotes(votes[referendumId]) + self?.presenter?.didReceiveAccountVotes( + votes[referendumId], + votingDistribution: votesResult + ) } case let .failure(error): self?.presenter?.didReceiveError(.accountVotesFailed(error)) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index ca35c4b054..92a47bfc6f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -23,6 +23,7 @@ final class ReferendumDetailsPresenter { private var referendum: ReferendumLocal private var actionDetails: ReferendumActionLocal? private var accountVotes: ReferendumAccountVoteLocal? + private var votingDistribution: CallbackStorageSubscriptionResult? private var referendumMetadata: ReferendumMetadataLocal? private var identities: [AccountAddress: AccountIdentity]? private var price: PriceData? @@ -37,12 +38,10 @@ final class ReferendumDetailsPresenter { private var statusViewModel: StatusTimeViewModel? init( - referendum: ReferendumLocal, chain: ChainModel, wallet: MetaAccountModel, accountManagementFilter: AccountManagementFilterProtocol, - accountVotes: ReferendumAccountVoteLocal?, - metadata: ReferendumMetadataLocal?, + initData: ReferendumDetailsInitData, interactor: ReferendumDetailsInteractorInputProtocol, wireframe: ReferendumDetailsWireframeProtocol, referendumViewModelFactory: ReferendumsModelFactoryProtocol, @@ -68,9 +67,12 @@ final class ReferendumDetailsPresenter { self.referendumMetadataViewModelFactory = referendumMetadataViewModelFactory self.statusViewModelFactory = statusViewModelFactory self.displayAddressViewModelFactory = displayAddressViewModelFactory - self.referendum = referendum - self.accountVotes = accountVotes - referendumMetadata = metadata + referendum = initData.referendum + accountVotes = initData.accountVotes + votingDistribution = initData.votesResult + blockNumber = initData.blockNumber + blockTime = initData.blockTime + referendumMetadata = initData.metadata self.chain = chain self.logger = logger self.localizationManager = localizationManager @@ -354,7 +356,15 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { } if wallet.fetch(for: chain.accountRequest()) != nil { - wireframe.showVote(from: view, referendum: referendum) + let initData = ReferendumVotingInitData( + votesResult: nil, + blockNumber: blockNumber, + blockTime: blockTime, + referendum: referendum, + lockDiff: nil + ) + + wireframe.showVote(from: view, referendum: referendum, initData: initData) } else if accountManagementFilter.accountManagementSupports(wallet: wallet, for: chain) { let message = R.string.localizable.commonChainCrowdloanAccountMissingMessage( chain.name, @@ -469,8 +479,12 @@ extension ReferendumDetailsPresenter: ReferendumDetailsInteractorOutputProtocol refreshIdentities() } - func didReceiveAccountVotes(_ votes: ReferendumAccountVoteLocal?) { + func didReceiveAccountVotes( + _ votes: ReferendumAccountVoteLocal?, + votingDistribution: CallbackStorageSubscriptionResult? + ) { accountVotes = votes + self.votingDistribution = votingDistribution provideYourVote() } diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift index 214a771682..e55b4d6a47 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsProtocols.swift @@ -36,7 +36,10 @@ protocol ReferendumDetailsInteractorInputProtocol: AnyObject { protocol ReferendumDetailsInteractorOutputProtocol: AnyObject { func didReceiveReferendum(_ referendum: ReferendumLocal) func didReceiveActionDetails(_ actionDetails: ReferendumActionLocal) - func didReceiveAccountVotes(_ votes: ReferendumAccountVoteLocal?) + func didReceiveAccountVotes( + _ votes: ReferendumAccountVoteLocal?, + votingDistribution: CallbackStorageSubscriptionResult? + ) func didReceiveMetadata(_ referendumMetadata: ReferendumMetadataLocal?) func didReceiveIdentities(_ identities: [AccountAddress: AccountIdentity]) func didReceivePrice(_ price: PriceData?) @@ -56,7 +59,11 @@ protocol ReferendumDetailsWireframeProtocol: AlertPresentable, ErrorPresentable, identities: [AccountAddress: AccountIdentity] ) - func showVote(from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal) + func showVote( + from view: ReferendumDetailsViewProtocol?, + referendum: ReferendumLocal, + initData: ReferendumVotingInitData + ) func showVoters( from view: ReferendumDetailsViewProtocol?, diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index aad80823a5..317f9c07fe 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -6,26 +6,55 @@ import SoraFoundation struct ReferendumDetailsViewFactory { static func createView( for state: GovernanceSharedState, - referendum: ReferendumLocal, - accountVotes: ReferendumAccountVoteLocal?, - metadata: ReferendumMetadataLocal? + initData: ReferendumDetailsInitData ) -> ReferendumDetailsViewProtocol? { guard let currencyManager = CurrencyManager.shared, let interactor = createInteractor( - for: referendum, + for: initData.referendum, currencyManager: currencyManager, state: state - ), - let chain = state.settings.value, - let assetInfo = chain.utilityAssetDisplayInfo(), - let wallet = SelectedWalletSettings.shared.value else { + ) else { return nil } let wireframe = ReferendumDetailsWireframe(state: state) - let localizationManager = LocalizationManager.shared + guard + let presenter = createPresenter( + interactor: interactor, + wireframe: wireframe, + currencyManager: currencyManager, + state: state, + initData: initData + ) else { + return nil + } + + let view = ReferendumDetailsViewController( + presenter: presenter, + localizationManager: LocalizationManager.shared + ) + + presenter.view = view + interactor.presenter = presenter + + return view + } + + private static func createPresenter( + interactor: ReferendumDetailsInteractor, + wireframe: ReferendumDetailsWireframe, + currencyManager: CurrencyManagerProtocol, + state: GovernanceSharedState, + initData: ReferendumDetailsInitData + ) -> ReferendumDetailsPresenter? { + guard + let chain = state.settings.value, + let assetInfo = chain.utilityAssetDisplayInfo(), + let wallet = SelectedWalletSettings.shared.value else { + return nil + } let balanceViewModelFactory = BalanceViewModelFactory( targetAssetInfo: assetInfo, @@ -52,13 +81,11 @@ struct ReferendumDetailsViewFactory { let metadataViewModelFactory = ReferendumMetadataViewModelFactory(indexFormatter: indexFormatter) - let presenter = ReferendumDetailsPresenter( - referendum: referendum, + return ReferendumDetailsPresenter( chain: chain, wallet: wallet, accountManagementFilter: AccountManagementFilter(), - accountVotes: accountVotes, - metadata: metadata, + initData: initData, interactor: interactor, wireframe: wireframe, referendumViewModelFactory: referendumViewModelFactory, @@ -69,19 +96,9 @@ struct ReferendumDetailsViewFactory { referendumMetadataViewModelFactory: metadataViewModelFactory, statusViewModelFactory: statusViewModelFactory, displayAddressViewModelFactory: DisplayAddressViewModelFactory(), - localizationManager: localizationManager, + localizationManager: LocalizationManager.shared, logger: Logger.shared ) - - let view = ReferendumDetailsViewController( - presenter: presenter, - localizationManager: localizationManager - ) - - presenter.view = view - interactor.presenter = presenter - - return view } private static func createInteractor( diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift index 64dceb1986..bed9efe667 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsWireframe.swift @@ -30,11 +30,16 @@ final class ReferendumDetailsWireframe: ReferendumDetailsWireframeProtocol { view?.controller.present(navigationController, animated: true) } - func showVote(from view: ReferendumDetailsViewProtocol?, referendum: ReferendumLocal) { + func showVote( + from view: ReferendumDetailsViewProtocol?, + referendum: ReferendumLocal, + initData: ReferendumVotingInitData + ) { guard let voteSetupView = ReferendumVoteSetupViewFactory.createView( for: state, - referendum: referendum.index + referendum: referendum.index, + initData: initData ) else { return } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift index cd857c6340..2a757438f8 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmPresenter.swift @@ -32,6 +32,7 @@ final class ReferendumVoteConfirmPresenter { private lazy var addressDisplayViewModelFactory = DisplayAddressViewModelFactory() init( + initData: ReferendumVotingInitData, vote: ReferendumNewVote, chain: ChainModel, selectedAccount: MetaChainAccountResponse, @@ -48,6 +49,11 @@ final class ReferendumVoteConfirmPresenter { self.vote = vote self.chain = chain self.selectedAccount = selectedAccount + votesResult = initData.votesResult + blockNumber = initData.blockNumber + blockTime = initData.blockTime + referendum = initData.referendum + lockDiff = initData.lockDiff self.dataValidatingFactory = dataValidatingFactory self.balanceViewModelFactory = balanceViewModelFactory self.referendumFormatter = referendumFormatter diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift index aebc568a2e..21b286d009 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -6,7 +6,8 @@ import SoraFoundation struct ReferendumVoteConfirmViewFactory { static func createView( for state: GovernanceSharedState, - newVote: ReferendumNewVote + newVote: ReferendumNewVote, + initData: ReferendumVotingInitData ) -> ReferendumVoteConfirmViewProtocol? { guard let currencyManager = CurrencyManager.shared, @@ -48,6 +49,7 @@ struct ReferendumVoteConfirmViewFactory { ) let presenter = ReferendumVoteConfirmPresenter( + initData: initData, vote: newVote, chain: chain, selectedAccount: selectedAccount, diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumVotingInitData.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumVotingInitData.swift new file mode 100644 index 0000000000..b9080a1c9c --- /dev/null +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/Model/ReferendumVotingInitData.swift @@ -0,0 +1,9 @@ +import Foundation + +struct ReferendumVotingInitData { + let votesResult: CallbackStorageSubscriptionResult? + let blockNumber: BlockNumber? + let blockTime: BlockTime? + let referendum: ReferendumLocal? + let lockDiff: GovernanceLockStateDiff? +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift index d9fb5ff064..bc9f8283b7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupPresenter.swift @@ -33,6 +33,7 @@ final class ReferendumVoteSetupPresenter { init( chain: ChainModel, referendumIndex: ReferendumIdLocal, + initData: ReferendumVotingInitData, dataValidatingFactory: GovernanceValidatorFactoryProtocol, balanceViewModelFactory: BalanceViewModelFactoryProtocol, referendumFormatter: LocalizableResource, @@ -45,6 +46,11 @@ final class ReferendumVoteSetupPresenter { logger: LoggerProtocol ) { self.chain = chain + votesResult = initData.votesResult + blockNumber = initData.blockNumber + blockTime = initData.blockTime + referendum = initData.referendum + lockDiff = initData.lockDiff self.referendumIndex = referendumIndex self.dataValidatingFactory = dataValidatingFactory self.balanceViewModelFactory = balanceViewModelFactory @@ -314,7 +320,15 @@ final class ReferendumVoteSetupPresenter { return } - self?.wireframe.showConfirmation(from: self?.view, vote: newVote) + let initData = ReferendumVotingInitData( + votesResult: self?.votesResult, + blockNumber: self?.blockNumber, + blockTime: self?.blockTime, + referendum: self?.referendum, + lockDiff: self?.lockDiff + ) + + self?.wireframe.showConfirmation(from: self?.view, vote: newVote, initData: initData) } } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift index 474dfe6c53..5c44fa3592 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupProtocols.swift @@ -31,5 +31,9 @@ protocol ReferendumVoteSetupInteractorOutputProtocol: ReferendumVoteInteractorOu protocol ReferendumVoteSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable, FeeRetryable, GovernanceErrorPresentable { - func showConfirmation(from view: ReferendumVoteSetupViewProtocol?, vote: ReferendumNewVote) + func showConfirmation( + from view: ReferendumVoteSetupViewProtocol?, + vote: ReferendumNewVote, + initData: ReferendumVotingInitData + ) } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index 521c7ded9a..3d449ef67e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -6,7 +6,8 @@ import SoraFoundation struct ReferendumVoteSetupViewFactory { static func createView( for state: GovernanceSharedState, - referendum: ReferendumIdLocal + referendum: ReferendumIdLocal, + initData: ReferendumVotingInitData ) -> ReferendumVoteSetupViewProtocol? { guard let currencyManager = CurrencyManager.shared, @@ -32,6 +33,7 @@ struct ReferendumVoteSetupViewFactory { wireframe: wireframe, dataValidatingFactory: dataValidatingFactory, referendum: referendum, + initData: initData, state: state ) else { return nil @@ -54,6 +56,7 @@ struct ReferendumVoteSetupViewFactory { wireframe: ReferendumVoteSetupWireframeProtocol, dataValidatingFactory: GovernanceValidatorFactoryProtocol, referendum: ReferendumIdLocal, + initData: ReferendumVotingInitData, state: GovernanceSharedState ) -> ReferendumVoteSetupPresenter? { guard @@ -83,6 +86,7 @@ struct ReferendumVoteSetupViewFactory { return ReferendumVoteSetupPresenter( chain: chain, referendumIndex: referendum, + initData: initData, dataValidatingFactory: dataValidatingFactory, balanceViewModelFactory: balanceViewModelFactory, referendumFormatter: NumberFormatter.index.localizableResource(), diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift index f4bf406d26..0e1aac0a5f 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupWireframe.swift @@ -7,10 +7,15 @@ final class ReferendumVoteSetupWireframe: ReferendumVoteSetupWireframeProtocol { self.state = state } - func showConfirmation(from view: ReferendumVoteSetupViewProtocol?, vote: ReferendumNewVote) { + func showConfirmation( + from view: ReferendumVoteSetupViewProtocol?, + vote: ReferendumNewVote, + initData: ReferendumVotingInitData + ) { guard let confirmView = ReferendumVoteConfirmViewFactory.createView( for: state, - newVote: vote + newVote: vote, + initData: initData ) else { return } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 0dd81f8c41..e58e59e307 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -230,14 +230,15 @@ extension ReferendumsPresenter: ReferendumsPresenterProtocol { return } - let accountVotes = voting?.value?.votes - - wireframe.showReferendumDetails( - from: view, + let initData = ReferendumDetailsInitData( referendum: referendum, - accountVotes: accountVotes?.votes[referendum.index], + votesResult: voting, + blockNumber: blockNumber, + blockTime: blockTime, metadata: referendumsMetadata?[referendum.index] ) + + wireframe.showReferendumDetails(from: view, initData: initData) } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 56f12bb2c6..16c7a6edeb 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -46,12 +46,7 @@ protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, Commo selectedChainAssetId: ChainAssetId? ) - func showReferendumDetails( - from view: ControllerBackedProtocol?, - referendum: ReferendumLocal, - accountVotes: ReferendumAccountVoteLocal?, - metadata: ReferendumMetadataLocal? - ) + func showReferendumDetails(from view: ControllerBackedProtocol?, initData: ReferendumDetailsInitData) func showUnlocksDetails(from view: ControllerBackedProtocol?) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index f7356bf089..a53fd8a66e 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -32,18 +32,11 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { view?.controller.present(navigationController, animated: true, completion: nil) } - func showReferendumDetails( - from view: ControllerBackedProtocol?, - referendum: ReferendumLocal, - accountVotes: ReferendumAccountVoteLocal?, - metadata: ReferendumMetadataLocal? - ) { + func showReferendumDetails(from view: ControllerBackedProtocol?, initData: ReferendumDetailsInitData) { guard let detailsView = ReferendumDetailsViewFactory.createView( for: state, - referendum: referendum, - accountVotes: accountVotes, - metadata: metadata + initData: initData ) else { return } From 740b4a337d194b2320c7928526bc90973e3459d5 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 13:10:50 +0500 Subject: [PATCH 203/229] improve loading for unlock flow --- novawallet.xcodeproj/project.pbxproj | 16 ++++++++++++++++ .../GovernanceUnlockConfirmPresenter.swift | 11 ++++------- .../GovernanceUnlockConfirmViewFactory.swift | 8 ++------ .../Model/GovernanceUnlockConfirmInitData.swift | 7 +++++++ .../GovernanceUnlockSetupPresenter.swift | 12 +++++++++--- .../GovernanceUnlockSetupProtocols.swift | 7 +------ .../GovernanceUnlockSetupViewFactory.swift | 6 +++++- .../GovernanceUnlockSetupWireframe.swift | 8 ++------ .../Model/GovernanceUnlockInitData.swift | 8 ++++++++ .../Referendums/ReferendumsPresenter.swift | 15 +++++++++++---- .../Referendums/ReferendumsProtocols.swift | 2 +- .../Referendums/ReferendumsWireframe.swift | 4 ++-- 12 files changed, 68 insertions(+), 36 deletions(-) create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInitData.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/Model/GovernanceUnlockInitData.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 323fb7cf99..66275470a8 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -1228,6 +1228,8 @@ 8476D3A127F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8476D3A027F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift */; }; 84770F25291F72D700852A33 /* ReferendumVotingInitData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84770F24291F72D700852A33 /* ReferendumVotingInitData.swift */; }; 84770F27291F7CD400852A33 /* ReferendumDetailsInitData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84770F26291F7CD400852A33 /* ReferendumDetailsInitData.swift */; }; + 84770F2A291F864500852A33 /* GovernanceUnlockInitData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84770F29291F864500852A33 /* GovernanceUnlockInitData.swift */; }; + 84770F2C291F893200852A33 /* GovernanceUnlockConfirmInitData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84770F2B291F893200852A33 /* GovernanceUnlockConfirmInitData.swift */; }; 8477DAA32888329800129B45 /* watchOnlyPreset.json in Resources */ = {isa = PBXBuildFile; fileRef = 8477DAA22888329800129B45 /* watchOnlyPreset.json */; }; 8477DAA6288832CB00129B45 /* WatchOnlyPresetRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8477DAA5288832CB00129B45 /* WatchOnlyPresetRepository.swift */; }; 84786DA825F9F58E0089DFF7 /* EraValidatorService+Fetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84786DA725F9F58E0089DFF7 /* EraValidatorService+Fetch.swift */; }; @@ -4219,6 +4221,8 @@ 8476D3A027F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppBrowserPhishingDetectedState.swift; sourceTree = ""; }; 84770F24291F72D700852A33 /* ReferendumVotingInitData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVotingInitData.swift; sourceTree = ""; }; 84770F26291F7CD400852A33 /* ReferendumDetailsInitData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumDetailsInitData.swift; sourceTree = ""; }; + 84770F29291F864500852A33 /* GovernanceUnlockInitData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockInitData.swift; sourceTree = ""; }; + 84770F2B291F893200852A33 /* GovernanceUnlockConfirmInitData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmInitData.swift; sourceTree = ""; }; 8477DAA22888329800129B45 /* watchOnlyPreset.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = watchOnlyPreset.json; sourceTree = ""; }; 8477DAA5288832CB00129B45 /* WatchOnlyPresetRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchOnlyPresetRepository.swift; sourceTree = ""; }; 84786DA725F9F58E0089DFF7 /* EraValidatorService+Fetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EraValidatorService+Fetch.swift"; sourceTree = ""; }; @@ -8900,6 +8904,14 @@ path = Fetch; sourceTree = ""; }; + 84770F28291F85D500852A33 /* Model */ = { + isa = PBXGroup; + children = ( + 84770F29291F864500852A33 /* GovernanceUnlockInitData.swift */, + ); + path = Model; + sourceTree = ""; + }; 847999B22888B46300D1BAD2 /* Address */ = { isa = PBXGroup; children = ( @@ -10573,6 +10585,7 @@ isa = PBXGroup; children = ( 84A9ECC0291292900094C763 /* GovernanceUnlockConfirmInteractorError.swift */, + 84770F2B291F893200852A33 /* GovernanceUnlockConfirmInitData.swift */, ); path = Model; sourceTree = ""; @@ -14226,6 +14239,7 @@ FD4B0C614F7A70D8FB51A1C3 /* GovernanceUnlockSetup */ = { isa = PBXGroup; children = ( + 84770F28291F85D500852A33 /* Model */, 847157842911367400D7D003 /* ViewModel */, 847157812911321000D7D003 /* View */, F4642DD5186EFA940518CCB4 /* GovernanceUnlockSetupProtocols.swift */, @@ -16588,6 +16602,7 @@ 84C5ADDF28133F3E006D7388 /* UnknownAddressView.swift in Sources */, 84F6B6502619E1ED0038F10D /* Int+Operations.swift in Sources */, 8487010E2907DF2F00F2C0C3 /* MultiValueView+Styles.swift in Sources */, + 84770F2A291F864500852A33 /* GovernanceUnlockInitData.swift in Sources */, 85547F698B551ACD387D84E2 /* SelectValidatorsStartViewController.swift in Sources */, 845B07F129159AE7005785D3 /* DemocracyVoting.swift in Sources */, 41B29C1C9239BB2DCB7903A7 /* SelectValidatorsStartViewFactory.swift in Sources */, @@ -17278,6 +17293,7 @@ 845B0817291902CF005785D3 /* Gov2LockStateFactory.swift in Sources */, 41DE96F778AE909978775438 /* ParitySignerTxQrViewController.swift in Sources */, 87F7556E02F6F5BB6F1B1AEA /* ParitySignerTxQrViewLayout.swift in Sources */, + 84770F2C291F893200852A33 /* GovernanceUnlockConfirmInitData.swift in Sources */, 84E90BA128D0B51000529633 /* CheckboxControlView.swift in Sources */, 821518375113295E41E0481C /* ParitySignerTxQrViewFactory.swift in Sources */, 641D7CF89F37B1890516015E /* ParitySignerTxScanProtocols.swift in Sources */, diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift index 4383549844..4f20e51af1 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmPresenter.swift @@ -1,7 +1,6 @@ import Foundation import BigInt import SoraFoundation -import BigInt final class GovernanceUnlockConfirmPresenter { weak var view: GovernanceUnlockConfirmViewProtocol? @@ -31,9 +30,7 @@ final class GovernanceUnlockConfirmPresenter { wireframe: GovernanceUnlockConfirmWireframeProtocol, chain: ChainModel, selectedAccount: MetaChainAccountResponse, - votingResult: CallbackStorageSubscriptionResult, - schedule: GovernanceUnlockSchedule, - blockNumber: BlockNumber, + initData: GovernanceUnlockConfirmInitData, balanceViewModelFactory: BalanceViewModelFactoryProtocol, lockChangeViewModelFactory: ReferendumLockChangeViewModelFactoryProtocol, dataValidatingFactory: GovernanceValidatorFactoryProtocol, @@ -44,9 +41,9 @@ final class GovernanceUnlockConfirmPresenter { self.wireframe = wireframe self.chain = chain self.selectedAccount = selectedAccount - self.votingResult = votingResult - unlockSchedule = schedule - self.blockNumber = blockNumber + votingResult = initData.votingResult + unlockSchedule = initData.unlockSchedule + blockNumber = initData.blockNumber self.balanceViewModelFactory = balanceViewModelFactory self.lockChangeViewModelFactory = lockChangeViewModelFactory self.dataValidatingFactory = dataValidatingFactory diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift index bfa9103a99..c533323986 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift @@ -5,9 +5,7 @@ import SoraFoundation struct GovernanceUnlockConfirmViewFactory { static func createView( for state: GovernanceSharedState, - votingResult: CallbackStorageSubscriptionResult, - schedule: GovernanceUnlockSchedule, - blockNumber: BlockNumber + initData: GovernanceUnlockConfirmInitData ) -> GovernanceUnlockConfirmViewProtocol? { guard let wallet = SelectedWalletSettings.shared.value, @@ -46,9 +44,7 @@ struct GovernanceUnlockConfirmViewFactory { wireframe: wireframe, chain: chain, selectedAccount: selectedAccount, - votingResult: votingResult, - schedule: schedule, - blockNumber: blockNumber, + initData: initData, balanceViewModelFactory: balanceViewModelFactory, lockChangeViewModelFactory: lockChangeViewModelFactory, dataValidatingFactory: dataValidatingFactory, diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInitData.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInitData.swift new file mode 100644 index 0000000000..eecf86580e --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/Model/GovernanceUnlockConfirmInitData.swift @@ -0,0 +1,7 @@ +import Foundation + +struct GovernanceUnlockConfirmInitData { + let votingResult: CallbackStorageSubscriptionResult + let unlockSchedule: GovernanceUnlockSchedule + let blockNumber: BlockNumber +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift index db3da83b20..d1ace4bf22 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupPresenter.swift @@ -20,6 +20,7 @@ final class GovernanceUnlockSetupPresenter { private var countdownTimer: CountdownTimer? init( + initData: GovernanceUnlockInitData, interactor: GovernanceUnlockSetupInteractorInputProtocol, wireframe: GovernanceUnlockSetupWireframeProtocol, balanceViewModelFactory: BalanceViewModelFactoryProtocol, @@ -27,6 +28,10 @@ final class GovernanceUnlockSetupPresenter { logger: LoggerProtocol, localizationManager: LocalizationManagerProtocol ) { + votingResult = initData.votingResult + unlockSchedule = initData.unlockSchedule + blockTime = initData.blockTime + blockNumber = initData.blockNumber self.interactor = interactor self.wireframe = wireframe self.balanceViewModelFactory = balanceViewModelFactory @@ -251,12 +256,13 @@ extension GovernanceUnlockSetupPresenter: GovernanceUnlockSetupPresenterProtocol return } - wireframe.showConfirm( - from: view, + let initData = GovernanceUnlockConfirmInitData( votingResult: votingResult, - schedule: unlockSchedule, + unlockSchedule: unlockSchedule, blockNumber: blockNumber ) + + wireframe.showConfirm(from: view, initData: initData) } } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift index c36799ef83..95ba77ac08 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupProtocols.swift @@ -13,10 +13,5 @@ protocol GovernanceUnlockSetupInteractorInputProtocol: GovernanceUnlockInteracto protocol GovernanceUnlockSetupInteractorOutputProtocol: GovernanceUnlockInteractorOutputProtocol {} protocol GovernanceUnlockSetupWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable { - func showConfirm( - from view: GovernanceUnlockSetupViewProtocol?, - votingResult: CallbackStorageSubscriptionResult, - schedule: GovernanceUnlockSchedule, - blockNumber: BlockNumber - ) + func showConfirm(from view: GovernanceUnlockSetupViewProtocol?, initData: GovernanceUnlockConfirmInitData) } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift index da93796e20..3b94389e50 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift @@ -2,7 +2,10 @@ import Foundation import SoraFoundation struct GovernanceUnlockSetupViewFactory { - static func createView(for state: GovernanceSharedState) -> GovernanceUnlockSetupViewProtocol? { + static func createView( + for state: GovernanceSharedState, + initData: GovernanceUnlockInitData + ) -> GovernanceUnlockSetupViewProtocol? { guard let interactor = createInteractor(for: state), let assetInfo = state.settings.value?.utilityAssetDisplayInfo(), @@ -20,6 +23,7 @@ struct GovernanceUnlockSetupViewFactory { let localizationManager = LocalizationManager.shared let presenter = GovernanceUnlockSetupPresenter( + initData: initData, interactor: interactor, wireframe: wireframe, balanceViewModelFactory: balanceViewModelFactory, diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift index 3d7089d07a..28c4831632 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupWireframe.swift @@ -9,15 +9,11 @@ final class GovernanceUnlockSetupWireframe: GovernanceUnlockSetupWireframeProtoc func showConfirm( from view: GovernanceUnlockSetupViewProtocol?, - votingResult: CallbackStorageSubscriptionResult, - schedule: GovernanceUnlockSchedule, - blockNumber: BlockNumber + initData: GovernanceUnlockConfirmInitData ) { guard let confirmView = GovernanceUnlockConfirmViewFactory.createView( for: state, - votingResult: votingResult, - schedule: schedule, - blockNumber: blockNumber + initData: initData ) else { return } diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/Model/GovernanceUnlockInitData.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/Model/GovernanceUnlockInitData.swift new file mode 100644 index 0000000000..098f63eca5 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/Model/GovernanceUnlockInitData.swift @@ -0,0 +1,8 @@ +import Foundation + +struct GovernanceUnlockInitData { + let votingResult: CallbackStorageSubscriptionResult? + let unlockSchedule: GovernanceUnlockSchedule? + let blockNumber: BlockNumber? + let blockTime: BlockTime? +} diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index e58e59e307..35900cd912 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -240,6 +240,17 @@ extension ReferendumsPresenter: ReferendumsPresenterProtocol { wireframe.showReferendumDetails(from: view, initData: initData) } + + func selectUnlocks() { + let initData = GovernanceUnlockInitData( + votingResult: voting, + unlockSchedule: unlockSchedule, + blockNumber: blockNumber, + blockTime: blockTime + ) + + wireframe.showUnlocksDetails(from: view, initData: initData) + } } extension ReferendumsPresenter: VoteChildPresenterProtocol { @@ -269,10 +280,6 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { selectedChainAssetId: chainAssetId ) } - - func selectUnlocks() { - wireframe.showUnlocksDetails(from: view) - } } extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index 16c7a6edeb..b39459c80d 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -48,5 +48,5 @@ protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, Commo func showReferendumDetails(from view: ControllerBackedProtocol?, initData: ReferendumDetailsInitData) - func showUnlocksDetails(from view: ControllerBackedProtocol?) + func showUnlocksDetails(from view: ControllerBackedProtocol?, initData: GovernanceUnlockInitData) } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index a53fd8a66e..811c680f14 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -46,8 +46,8 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { view?.controller.navigationController?.pushViewController(detailsView.controller, animated: true) } - func showUnlocksDetails(from view: ControllerBackedProtocol?) { - guard let unlocksView = GovernanceUnlockSetupViewFactory.createView(for: state) else { + func showUnlocksDetails(from view: ControllerBackedProtocol?, initData: GovernanceUnlockInitData) { + guard let unlocksView = GovernanceUnlockSetupViewFactory.createView(for: state, initData: initData) else { return } From 7134aca87cc9a5ad8468dfa6723b1041771a127f Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 17:07:39 +0500 Subject: [PATCH 204/229] fix no account in the wallet --- .../ReferendumDetails/ReferendumDetailsPresenter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift index 92a47bfc6f..d6dfbcb1f8 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsPresenter.swift @@ -365,7 +365,7 @@ extension ReferendumDetailsPresenter: ReferendumDetailsPresenterProtocol { ) wireframe.showVote(from: view, referendum: referendum, initData: initData) - } else if accountManagementFilter.accountManagementSupports(wallet: wallet, for: chain) { + } else if accountManagementFilter.canAddAccount(to: wallet, chain: chain) { let message = R.string.localizable.commonChainCrowdloanAccountMissingMessage( chain.name, preferredLanguages: selectedLocale.rLanguages From d6c5ce48e67e8b95c9f8b62697c549398b1acb8a Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 17:39:38 +0500 Subject: [PATCH 205/229] cancel cancellables from subscription when going background --- .../Governance/Referendums/ReferendumsInteractor.swift | 1 + .../Governance/Subscription/Gov1SubscriptionFactory.swift | 8 ++++++++ .../Governance/Subscription/Gov2SubscriptionFactory.swift | 8 ++++++++ .../Subscription/GovernanceSubscriptionProtocol.swift | 2 ++ 4 files changed, 19 insertions(+) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 304ca05123..73e5584168 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -489,5 +489,6 @@ extension ReferendumsInteractor: SelectedCurrencyDepending { extension ReferendumsInteractor: ApplicationHandlerDelegate { func didReceiveDidEnterBackground(notification _: Notification) { clearCancellable() + governanceState.subscriptionFactory?.cancelCancellable() } } diff --git a/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift b/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift index bb9c7062ae..d2dc531bb7 100644 --- a/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift +++ b/novawallet/Modules/Vote/Governance/Subscription/Gov1SubscriptionFactory.swift @@ -177,6 +177,14 @@ final class Gov1SubscriptionFactory: AnyCancellableCleaning { } extension Gov1SubscriptionFactory: GovernanceSubscriptionFactoryProtocol { + func cancelCancellable() { + let keys = cancellables.keys + + for key in keys { + clear(cancellable: &cancellables[key]) + } + } + func subscribeToReferendum( _ target: AnyObject, referendumIndex: UInt, diff --git a/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift b/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift index 8214c8871d..d7d7a9b42a 100644 --- a/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift +++ b/novawallet/Modules/Vote/Governance/Subscription/Gov2SubscriptionFactory.swift @@ -173,6 +173,14 @@ final class Gov2SubscriptionFactory: AnyCancellableCleaning { } extension Gov2SubscriptionFactory: GovernanceSubscriptionFactoryProtocol { + func cancelCancellable() { + let keys = cancellables.keys + + for key in keys { + clear(cancellable: &cancellables[key]) + } + } + func subscribeToReferendum( _ target: AnyObject, referendumIndex: ReferendumIdLocal, diff --git a/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift b/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift index 46139c161e..5ab536b995 100644 --- a/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift +++ b/novawallet/Modules/Vote/Governance/Subscription/GovernanceSubscriptionProtocol.swift @@ -23,4 +23,6 @@ protocol GovernanceSubscriptionFactoryProtocol { ) func unsubscribeFromAccountVotes(_ target: AnyObject, accountId: AccountId) + + func cancelCancellable() } From d623665ad54facfcfa33e889f2c9a6f8b9413bf6 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 18:41:26 +0500 Subject: [PATCH 206/229] add compact format for period --- .../TimeInterval+Localization.swift | 20 +++++++++++++++++++ .../Foundation/TimeInterval+Time.swift | 1 + ...ReferendumLockChangeViewModelFactory.swift | 6 +++--- novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift b/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift index cf3d7e1b30..2337472db9 100644 --- a/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift +++ b/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift @@ -1,4 +1,5 @@ import Foundation +import SoraFoundation extension TimeInterval { func localizedDaysHours(for locale: Locale) -> String { @@ -37,6 +38,25 @@ extension TimeInterval { return localizedDaysHours(for: locale) } + func localizedFractionDays(for locale: Locale, shouldAnnotate: Bool) -> String { + let days = fractionDaysFromSeconds + let formatter = NumberFormatter.decimalFormatter(precision: 1, rounding: .down) + let optDaysString = formatter.stringFromDecimal(days) + + if shouldAnnotate { + if let daysString = optDaysString { + return R.string.localizable.commonDaysFractionFormat( + daysString, + preferredLanguages: locale.rLanguages + ) + } else { + return "" + } + } else { + return optDaysString ?? "" + } + } + func localizedDaysOrTime(for locale: Locale) -> String? { let days = daysFromSeconds diff --git a/novawallet/Common/Extension/Foundation/TimeInterval+Time.swift b/novawallet/Common/Extension/Foundation/TimeInterval+Time.swift index 61ed8ddced..94c84c5538 100644 --- a/novawallet/Common/Extension/Foundation/TimeInterval+Time.swift +++ b/novawallet/Common/Extension/Foundation/TimeInterval+Time.swift @@ -16,6 +16,7 @@ extension TimeInterval { var seconds: TimeInterval { self / 1000 } var minutesFromSeconds: Int { Int(self / Self.secondsInMinute) } var daysFromSeconds: Int { Int(self / Self.secondsInDay) } + var fractionDaysFromSeconds: Decimal { Decimal(self) / Decimal(Self.secondsInDay) } var secondsFromDays: TimeInterval { self * Self.secondsInDay } var hoursFromSeconds: Int { Int(self / Self.secondsInHour) } var secondsFromHours: TimeInterval { self * Self.secondsInHour } diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift index 871a0d6aaa..45c8d29639 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ViewModel/ReferendumLockChangeViewModelFactory.swift @@ -240,7 +240,7 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac let fromBlock = max(initLockedUntil, blockNumber) let fromPeriod = blockNumber.secondsTo(block: fromBlock, blockDuration: blockTime) - let fromPeriodString = fromPeriod.localizedDaysHoursIncludingZero(for: locale) + let fromPeriodString = fromPeriod.localizedFractionDays(for: locale, shouldAnnotate: false) let toPeriodString: String let change: ReferendumLockTransitionViewModel.Change? @@ -249,7 +249,7 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac let toBlock = max(resultLockedUntil, blockNumber) let toPeriod = blockNumber.secondsTo(block: toBlock, blockDuration: blockTime) - toPeriodString = toPeriod.localizedDaysHoursIncludingZero(for: locale) + toPeriodString = toPeriod.localizedFractionDays(for: locale, shouldAnnotate: true) if fromPeriod < toPeriod, (toPeriod - fromPeriod).hoursFromSeconds > 0 { change = .init( @@ -271,7 +271,7 @@ extension ReferendumLockChangeViewModelFactory: ReferendumLockChangeViewModelFac change = nil } } else { - toPeriodString = fromPeriodString + toPeriodString = fromPeriod.localizedFractionDays(for: locale, shouldAnnotate: true) change = nil } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 5a33ad7758..2f30d91f49 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1082,3 +1082,4 @@ "gov.vote.treshold.function.simpleMajority" = "Simple Majority"; "gov.vote.treshold.function.superMajorityAgainst" = "Super Majority Against"; "gov.vote.treshold.function.superMajorityApprove" = "Super Majority Approve"; +"common.days.fraction.format" = "%@ days"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 214ef7c9eb..7cd5cfcdcd 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1083,3 +1083,4 @@ "gov.vote.treshold.function.simpleMajority" = "Простое большинство"; "gov.vote.treshold.function.superMajorityAgainst" = "Супербольшинство против"; "gov.vote.treshold.function.superMajorityApprove" = "Супербольшинство за"; +"common.days.fraction.format" = "%@ дней"; From 7c0db8d5a7206e010ab2c6b385f5320c2fe8b191 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 21:37:06 +0500 Subject: [PATCH 207/229] fix locale --- .../Common/Extension/Foundation/TimeInterval+Localization.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift b/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift index 2337472db9..a87b82af41 100644 --- a/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift +++ b/novawallet/Common/Extension/Foundation/TimeInterval+Localization.swift @@ -41,6 +41,7 @@ extension TimeInterval { func localizedFractionDays(for locale: Locale, shouldAnnotate: Bool) -> String { let days = fractionDaysFromSeconds let formatter = NumberFormatter.decimalFormatter(precision: 1, rounding: .down) + formatter.locale = locale let optDaysString = formatter.stringFromDecimal(days) if shouldAnnotate { From d018a74b93cfe8c4576a9874d6a6af44a6aae30a Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 21:42:55 +0500 Subject: [PATCH 208/229] fix full details proposer click --- .../ReferendumFullDetails/ReferendumFullDetailsPresenter.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift index 1d3f7bbf72..882cd2c139 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsPresenter.swift @@ -162,7 +162,8 @@ extension ReferendumFullDetailsPresenter: ReferendumFullDetailsPresenterProtocol } func presentProposer() { - guard let address = try? referendum.proposer?.toAddress(using: chain.chainFormat) else { + let optAccountId = referendum.proposer ?? metadata?.proposerAccountId(for: chain.chainFormat) + guard let address = try? optAccountId?.toAddress(using: chain.chainFormat) else { return } From 2b92eff7ca043514ce8bbd4fc0b3b3dbfcd2fc8d Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 22:19:46 +0500 Subject: [PATCH 209/229] add empty state --- .../Referendums/ReferendumsViewManager.swift | 60 +++++++++++++------ .../ViewModel/ReferendumsModelFactory.swift | 3 +- .../ViewModel/ReferendumsViewModel.swift | 9 +++ novawallet/en.lproj/Localizable.strings | 1 + novawallet/ru.lproj/Localizable.strings | 1 + 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift index 8572a68802..70c0828c89 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsViewManager.swift @@ -45,7 +45,7 @@ extension ReferendumsViewManager: UITableViewDataSource { let referendumsSection = section - 1 switch referendumsViewModel.sections[referendumsSection] { case let .active(_, cells), let .completed(_, cells): - return cells.count + return !cells.isEmpty ? cells.count : 1 } } } @@ -61,16 +61,26 @@ extension ReferendumsViewManager: UITableViewDataSource { return unlocksCell } else { - let cell: ReferendumTableViewCell = tableView.dequeueReusableCell(for: indexPath) - cell.applyStyle() - let referendumsSection = indexPath.section - 1 let section = referendumsViewModel.sections[referendumsSection] - switch section { - case let .active(_, cellModels), let .completed(_, cellModels): - let cellModel = cellModels[indexPath.row].viewModel - cell.view.bind(viewModel: cellModel) + + if section.isEmpty { + let cell: BlurredTableViewCell = tableView.dequeueReusableCell(for: indexPath) + let text = R.string.localizable.govEmptyList(preferredLanguages: locale.rLanguages) + cell.view.bind(image: R.image.iconEmptyHistory(), text: text) + cell.applyStyle() + return cell + } else { + let cell: ReferendumTableViewCell = tableView.dequeueReusableCell(for: indexPath) + cell.applyStyle() + + switch section { + case let .active(_, cellModels), let .completed(_, cellModels): + let cellModel = cellModels[indexPath.row].viewModel + cell.view.bind(viewModel: cellModel) + return cell + } } } } @@ -85,6 +95,11 @@ extension ReferendumsViewManager: UITableViewDelegate { } else { let referendumsSection = indexPath.section - 1 let section = referendumsViewModel.sections[referendumsSection] + + guard !section.isEmpty else { + return + } + switch section { case let .active(_, cellModels), let .completed(_, cellModels): let referendumIndex = cellModels[indexPath.row].referendumIndex @@ -119,6 +134,7 @@ extension ReferendumsViewManager: UITableViewDelegate { guard section > 0 else { return 0 } + let referendumsSection = section - 1 let sectionModel = referendumsViewModel.sections[referendumsSection] switch sectionModel { @@ -133,18 +149,24 @@ extension ReferendumsViewManager: UITableViewDelegate { } func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - guard indexPath.section > 0 else { + if indexPath.section == 0 { return Constants.unlocksCellHeight - } - let referendumsSection = indexPath.section - 1 - let sectionModel = referendumsViewModel.sections[referendumsSection] - switch sectionModel { - case let .active(_, cells), let .completed(_, cells): - switch cells[indexPath.row].viewModel { - case .loaded, .cached: + } else { + let referendumsSection = indexPath.section - 1 + let sectionModel = referendumsViewModel.sections[referendumsSection] + + if sectionModel.isEmpty { return UITableView.automaticDimension - case .loading: - return Constants.referendumCellMinimumHeight + } else { + switch sectionModel { + case let .active(_, cells), let .completed(_, cells): + switch cells[indexPath.row].viewModel { + case .loaded, .cached: + return UITableView.automaticDimension + case .loading: + return Constants.referendumCellMinimumHeight + } + } } } } @@ -208,6 +230,7 @@ extension ReferendumsViewManager: VoteChildViewProtocol { tableView.delegate = self tableView.registerClassForCell(ReferendumTableViewCell.self) tableView.registerClassForCell(ReferendumsUnlocksTableViewCell.self) + tableView.registerClassForCell(BlurredTableViewCell.self) tableView.registerHeaderFooterView(withClass: VoteStatusSectionView.self) tableView.reloadData() } @@ -217,6 +240,7 @@ extension ReferendumsViewManager: VoteChildViewProtocol { tableView.delegate = nil tableView.unregisterClassForCell(ReferendumTableViewCell.self) tableView.unregisterClassForCell(ReferendumsUnlocksTableViewCell.self) + tableView.unregisterClassForCell(BlurredTableViewCell.self) tableView.unregisterHeaderFooterView(withClass: VoteStatusSectionView.self) tableView.reloadData() } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 8619aaae06..6322602ade 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -534,7 +534,8 @@ extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { referendum.state.completed ? completed.append(viewModel) : active.append(viewModel) } var sections: [ReferendumsSection] = [] - if !active.isEmpty { + if !active.isEmpty || completed.isEmpty { + // still add empty section to display empty state let title = Strings.governanceReferendumsActive(preferredLanguages: input.locale.rLanguages) sections.append(.active(.loaded(value: title), active)) } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsViewModel.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsViewModel.swift index 5a98452737..9a09339671 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsViewModel.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsViewModel.swift @@ -5,6 +5,15 @@ struct ReferendumsViewModel { enum ReferendumsSection { case active(LoadableViewModelState, [ReferendumsCellViewModel]) case completed(LoadableViewModelState, [ReferendumsCellViewModel]) + + var isEmpty: Bool { + switch self { + case let .active(_, array): + return array.isEmpty + case let .completed(_, array): + return array.isEmpty + } + } } struct ReferendumsCellViewModel { diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 2f30d91f49..9729a58502 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1083,3 +1083,4 @@ "gov.vote.treshold.function.superMajorityAgainst" = "Super Majority Against"; "gov.vote.treshold.function.superMajorityApprove" = "Super Majority Approve"; "common.days.fraction.format" = "%@ days"; +"gov.empty.list" = "Referenda information\nwill appear here when they start"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 7cd5cfcdcd..20f267efce 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1084,3 +1084,4 @@ "gov.vote.treshold.function.superMajorityAgainst" = "Супербольшинство против"; "gov.vote.treshold.function.superMajorityApprove" = "Супербольшинство за"; "common.days.fraction.format" = "%@ дней"; +"gov.empty.list" = "Информация о референдумах\nпоявится здесь, когда они начнутся"; From ae3786d2415c3a1fb471f729095f231166de321f Mon Sep 17 00:00:00 2001 From: ERussel Date: Sat, 12 Nov 2022 22:47:36 +0500 Subject: [PATCH 210/229] fix timer on main screen --- .../Vote/Governance/Referendums/ReferendumsPresenter.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index 35900cd912..b9f1a52aea 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -206,7 +206,7 @@ final class ReferendumsPresenter { result[model.key] = .init( viewModel: updatedViewModel, - timeInterval: remainedTime, + timeInterval: time, updateModelClosure: timeModel.updateModelClosure ) } @@ -313,7 +313,6 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { self.blockNumber = blockNumber interactor.refresh() - updateTimeModels() } func didReceiveBlockTime(_ blockTime: BlockTime) { From ec27dfa665a76198c161dcd3e0fe82d1131c80d6 Mon Sep 17 00:00:00 2001 From: ERussel Date: Sun, 13 Nov 2022 01:05:09 +0500 Subject: [PATCH 211/229] fix localization --- .../ReferendumFullDetailsViewLayout.swift | 2 +- .../ReferendumStateLocal+Presenter.swift | 4 +- .../ViewModel/ReferendumsModelFactory.swift | 2 +- novawallet/en.lproj/Localizable.strings | 166 ++++++++-------- novawallet/ru.lproj/Localizable.strings | 181 +++++++++--------- 5 files changed, 173 insertions(+), 182 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift index 2cad51c418..d3fb3eee86 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewLayout.swift @@ -95,7 +95,7 @@ final class ReferendumFullDetailsViewLayout: UIView { if let amount = viewModel.amount { let amountCell = createBalanceCell( - with: R.string.localizable.govRequestedAmount(preferredLanguages: locale.rLanguages), + with: R.string.localizable.commonRequestedAmount(preferredLanguages: locale.rLanguages), viewModel: amount ) diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift index f98e8cf5b3..300c5c0caf 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumStateLocal+Presenter.swift @@ -81,7 +81,7 @@ extension Referenda.Curve { case .steppedDecreasing: return R.string.localizable.govSteppedDecreasing(preferredLanguages: locale.rLanguages) case .unknown: - return R.string.localizable.govUnknown(preferredLanguages: locale.rLanguages) + return R.string.localizable.commonUnknown(preferredLanguages: locale.rLanguages) } } } @@ -98,7 +98,7 @@ extension Democracy.VoteThreshold { return R.string.localizable.govVoteTresholdFunctionSuperMajorityApprove( preferredLanguages: locale.rLanguages) case .unknown: - return R.string.localizable.govUnknown( + return R.string.localizable.commonUnknown( preferredLanguages: locale.rLanguages) } } diff --git a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift index 6322602ade..f0192fb5f6 100644 --- a/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift +++ b/novawallet/Modules/Vote/Governance/ViewModel/ReferendumsModelFactory.swift @@ -540,7 +540,7 @@ extension ReferendumsModelFactory: ReferendumsModelFactoryProtocol { sections.append(.active(.loaded(value: title), active)) } if !completed.isEmpty { - let title = Strings.governanceReferendumsCompleted(preferredLanguages: input.locale.rLanguages) + let title = Strings.commonCompleted(preferredLanguages: input.locale.rLanguages) sections.append(.completed(.loaded(value: title), completed)) } return sections diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 9729a58502..58f15f31cb 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -288,7 +288,6 @@ "common.available.format" = "Available: %@"; "staking.rewards.learn.more" = "Learn more about rewards"; "common.error.no.data.retrieved" = "No data retrieved."; -"common.error.no.data.retrieved_v3_9_1" = "No data retrieved"; "staking.reward.payouts.empty.rewards" = "Perfect! All rewards are paid."; "staking.reward.details.validator" = "Validator"; "common.insufficient.balance" = "Insufficient balance"; @@ -540,6 +539,7 @@ "import.json.unsupported.ethereum.crypto.message" = "Cannot import account with Substrate secret into the network with Ethereum encryption"; "import.json.unsupported.substrate.crypto.message" = "Cannot import account with Ethereum secret into the network with Substrate encryption"; "common.tx.details" = "Transaction details"; +"common.unknown" = "Unknown"; "staking.month.period.title" = "Monthly"; "staking.year.period.title" = "Yearly"; "qr.scan.error.no.info" = "QR can't be decoded"; @@ -576,7 +576,6 @@ "account.create.details_v2_2_0" = "Do not use clipboard or screenshots on your mobile device, try to find secure methods for backup (e.g. paper)"; "crowdloan.list.section.format_v2_2_0" = "Choose parachains to contribute your %@. You'll get back your contributed tokens, and if parachain wins a slot, you'll receive rewards after the end of the auction"; "crowdloan.empty.message_v2_2_0" = "Crowdloans will be displayed here"; -"crowdloan.empty.message_v3_9_1" = "Crowdloans information\nwill appear here when they start"; "common.existential.warning.message_v2_2_0" = "Your account will be removed from blockchain after this operation cause it makes total balance lower than minimal"; "wallet.send.existential.warning_v2_2_0" = "Your account will be removed from blockchain after transfer cause it makes total balance lower than minimal"; "account.backup.mnemonic.title" = "Write down the phrase and store it in a safe place"; @@ -977,110 +976,107 @@ "yield.boost.task.not.found.message" = "Yield boost already disabled for the selected collator"; "common.not.available" = "N/A"; "wallet.account.locks.crowdloans" = "Crowdloans"; +"common.unlock" = "Unlock"; +"gov.voters.empty" = "List of voters will appear here"; "tabbar.vote.title" = "Vote"; -"tabbar.governance.title" = "Governance"; -"governance.referendums.status.preparing" = "preparing"; -"governance.referendums.status.preparing.inqueue" = "in queue"; -"governance.referendums.status.passing" = "passing"; -"governance.referendums.status.not.passing" = "not passing"; -"governance.referendums.status.approved" = "approved"; -"governance.referendums.status.rejected" = "rejected"; -"governance.referendums.status.cancelled" = "cancelled"; -"governance.referendums.status.timedOut" = "timed out"; -"governance.referendums.status.killed" = "killed"; -"governance.referendums.status.executed" = "executed"; - -"governance.referendums.time.deciding" = "Deciding in %@"; -"governance.referendums.time.timeout" = "Time out in %@"; +"gov.common.amount.conviction.format" = "%@ × %@x"; +"gov.referendum.description.fallback" = "Only the proposer can edit this description and the title. If you own proposer\'s account, visit Polkassembly and fill in information about your proposal"; +"gov.voters.nay" = "Nay votes"; +"gov.voters.aye" = "Aye votes"; +"gov.support.curve" = "Support curve"; +"gov.approve.curve" = "Approve curve"; +"gov.call.hash" = "Call hash"; +"gov.electorate" = "Electorate"; +"gov.turnout" = "Turnout"; +"gov.vote.threshold" = "Vote threshold"; +"gov.beneficiary" = "Beneficiary"; +"gov.deposit" = "Deposit"; +"gov.proposer" = "Proposer"; +"common.too.long.preview" = "Too long for preview"; +"gov.parameters.json" = "Parameters JSON"; +"common.requested.amount" = "Requested amount"; +"gov.details.voting.status" = "Voting status"; +"gov.full.details" = "Full details"; +"gov.vote" = "Vote"; +"gov.referendum.details.timeline.title" = "Timeline"; +"governance.nay" = "Nay"; +"governance.aye" = "Aye"; +"gov.track.big.spender" = "Treasury: big spend"; +"gov.track.medium.spender" = "Treasury: medium spend"; +"gov.track.small.spender" = "Treasury: Small spend"; +"gov.track.big.tipper" = "Treasury: big tips"; +"gov.track.small.tipper" = "Treasury: small tips"; +"gov.track.referendum.killer" = "governance: killer"; +"gov.track.referendum.canceller" = "governance: canceller"; +"gov.track.auction.admin" = "crowdloans"; +"gov.track.general.admin" = "governance: registrar"; +"gov.track.fellowship.admin" = "fellowship: admin"; +"gov.track.lease.admin" = "Governance: lease"; +"gov.track.treasurer" = "Treasury: ANY"; +"gov.track.staking.admin" = "staking"; +"gov.track.whitelisted.caller" = "fellowship: whitelist"; +"gov.track.root" = "main agenda"; "governance.referendums.time.execute" = "Execute in %@"; -"governance.referendums.time.waiting.deposit" = "Waiting for deposit"; "governance.referendums.time.approve" = "Approve in %@"; "governance.referendums.time.reject" = "Reject in %@"; - -"governance.referendums.threshold" = "Threshold: %@ of %@"; +"governance.referendums.time.timeout" = "Time out in %@"; +"governance.referendums.time.waiting.deposit" = "Waiting for deposit"; +"governance.referendums.time.deciding" = "Deciding in %@"; +"governance.referendums.status.killed" = "Killed"; +"governance.referendums.status.executed" = "Executed"; +"governance.referendums.status.preparing" = "Preparing"; +"governance.referendums.status.rejected" = "Rejected"; +"governance.referendums.status.not.passing" = "Not passing"; +"governance.referendums.status.passing" = "Passing"; +"governance.referendums.status.cancelled" = "Cancelled"; +"governance.referendums.status.timedOut" = "Timed out"; +"governance.referendums.status.approved" = "Approved"; "governance.referendums.your.vote" = "Your vote: %@ votes"; -"governance.referendums.active" = "Ongoing"; -"governance.referendums.completed" = "Completed"; -"governance.ayes.format" = "Aye: %@"; -"governance.nays.format" = "Nay: %@"; +"governance.referendums.threshold" = "Threshold: %@ of %@"; +"gov.referendum.title.fallback" = "Referendum %@"; +"tabbar.governance.title" = "Governance"; "governance.to.pass.format" = "To pass: %@"; -"governance.aye" = "Aye"; -"governance.nay" = "Nay"; -"gov.track.root" = "Main agenda"; -"gov.track.auction.admin" = "Crowdloans"; -"gov.track.staking.admin" = "Staking"; -"gov.track.lease.admin" = "Governance: Lease"; -"gov.track.general.admin" = "Governance: Registrar"; -"gov.track.referendum.canceller" = "Governance: Canceller"; -"gov.track.referendum.killer" = "Governance: Killer"; -"gov.track.treasurer" = "Treasury: Any"; -"gov.track.small.tipper" = "Treasury: Small tips"; -"gov.track.big.tipper" = "Treasury: Big tips"; -"gov.track.small.spender" = "Treasury: Small Spend"; -"gov.track.medium.spender" = "Treasury: Medium Spend"; -"gov.track.big.spender" = "Treasury: Big Spend"; -"gov.track.whitelisted.caller" = "Fellowship: Whitelist"; -"gov.track.fellowship.admin" = "Fellowship: Admin"; -"gov.voters.aye" = "Aye votes"; -"gov.voters.nay" = "Nay votes"; +"governance.nays.format" = "Nay: %@"; +"governance.ayes.format" = "Aye: %@"; +"common.completed" = "Completed"; +"governance.referendums.active" = "Ongoing"; +"common.read.more" = "Read more"; "gov.common.votes.format" = "%@ votes"; -"gov.common.amount.conviction.format" = "%@ × %@x"; -"gov.voters.empty" = "List of voters will appear here"; +"gov.timeline.created" = "Created"; "gov.vote.conviction.title" = "Multiply votes by increasing locking period"; -"common.gov.lock" = "Governance lock"; +"gov.vote.setup.title.format" = "Vote for %@"; "common.locking.period" = "Locking period"; +"common.gov.lock" = "Governance lock"; +"common. maximum" = "%@ maximum"; "gov.vote.setup.hint" = "After locking period don’t forget to unlock your tokens"; -"gov.vote.setup.title.format" = "Vote for %@"; -"common.available.prefix" = "Available:"; -"common.maximum" = "%@ maximum"; -"gov.referendum.details.timeline.title" = "Timeline"; -"gov.your.vote" = "Your vote"; -"common.amount.too.big" = "Amount is too big"; -"gov.not.enough.vote.tokens" = "Sorry, you don’t have enough available tokens to vote. Available to vote: %@"; -"gov.referendum.completed.title" = "Referendum is completed"; -"gov.referendum.completed.message" = "Referendum is completed and voting has finished"; -"gov.already.delegating.votes.title" = "Already delegating votes"; -"gov.already.delegating.votes.message" = "You are delegating votes for selected referendum’s track. Please, either ask your delegatee to vote or remove delegation to be able to vote directly."; -"gov.max.votes.reached.title" = "Maximum number of votes reached"; +"gov.revote" = "Revote"; "gov.max.votes.reached.message" = "You have reached a maximum of %@ votes for track"; -"gov.reuse.governance.locks" = "Reuse governance lock: %@"; +"gov.max.votes.reached.title" = "Maximum number of votes reached"; +"gov.already.delegating.votes.message" = "You are delegating votes for selected referendum’s track. Please either ask your delegatee to vote or remove delegation to be able to vote directly."; +"gov.already.delegating.votes.title" = "Already delegating votes"; +"gov.referendum.completed.message" = "Referendum is completed and voting has finished"; +"gov.referendum.completed.title" = "Referendum is completed"; +"gov.not.enough.vote.tokens" = "You don’t have enough available tokens to vote. Available to vote: %@."; +"common.amount.too.big" = "Amount is too big"; "gov.reuse.all.locks" = "Reuse all locks: %@"; -"gov.vote" = "Vote"; -"gov.revote" = "Revote"; -"gov.details.voting.status" = "Voting status"; -"common.requested.amount" = "Requested amount"; -"common.react.comment" = "Comment and react"; +"gov.reuse.governance.locks" = "Reuse governance lock: %@"; +"common.unlockable" = "Unlockable"; +"gov.remains.locked.suffix" = "remains locked in %@"; +"governance.referendums.status.preparing.inqueue" = "in queue"; +"common.available.prefix" = "Available:"; +"gov.your.vote" = "Your vote"; "common.use.dapp" = "Use Nova Featured websites"; -"gov.timeline.created" = "Created"; "gov.timeline.voting.format" = "Voting: %@"; "gov.timeline.voted.format" = "Voted: %@"; -"common.read.more" = "Read more"; -"gov.referendum.title.fallback" = "Referendum %@"; -"gov.referendum.description.fallback" = "Only the proposer can edit this description and the title. If you own proposer's account, visit Polkassembly and fill in information about your proposal"; -"gov.full.details" = "Full details"; -"gov.proposer" = "Proposer"; -"gov.deposit" = "Deposit"; -"gov.beneficiary" = "Beneficiary"; -"gov.requested.amount" = "Requested amount"; -"gov.approve.curve" = "Approve Curve"; -"gov.support.curve" = "Support Curve"; -"gov.vote.threshold" = "Vote threshold"; -"gov.turnout" = "Turnout"; -"gov.electorate" = "Electorate"; -"gov.call.hash" = "Call Hash"; -"gov.parameters.json" = "Parameters JSON"; -"common.copy" = "Copy"; -"common.too.long.preview" = "Too long for preview"; "gov.linear.decreasing" = "Linear Decreasing"; "gov.stepped.decreasing" = "Stepped Decreasing"; "gov.reciprocal" = "Reciprocal"; -"gov.unknown" = "Unknown"; "gov.in.queue.counter" = "(%@ of %@)"; -"common.unlock" = "Unlock"; -"common.unlockable" = "Unlockable"; -"gov.remains.locked.suffix" = " remains locked in %@"; "gov.vote.treshold.function.simpleMajority" = "Simple Majority"; "gov.vote.treshold.function.superMajorityAgainst" = "Super Majority Against"; "gov.vote.treshold.function.superMajorityApprove" = "Super Majority Approve"; "common.days.fraction.format" = "%@ days"; "gov.empty.list" = "Referenda information\nwill appear here when they start"; +"common.copy" = "Copy"; +"crowdloan.empty.message_v3_9_1" = "Crowdloans information\nwill appear here when they start"; +"common.error.no.data.retrieved_v3_9_1" = "No data retrieved"; \ No newline at end of file diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 20f267efce..8f3136de32 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -288,7 +288,6 @@ "common.available.format" = "Доступно: %@"; "staking.rewards.learn.more" = "Подробнее о вознаграждениях"; "common.error.no.data.retrieved" = "Данные не получены."; -"common.error.no.data.retrieved_v3_9_1" = "Данные не получены"; "staking.reward.payouts.empty.rewards" = "Прекрасно! Все вознаграждения выплачены."; "staking.reward.details.validator" = "Валидатор"; "common.insufficient.balance" = "Недостаточный баланс"; @@ -540,6 +539,7 @@ "import.json.unsupported.ethereum.crypto.message" = "Не поддерживается импорт аккаунта с Substrate секретом в сеть с Ethereum шифрованием"; "import.json.unsupported.substrate.crypto.message" = "Не поддерживается импорт аккаунта с Ethereum секретом в сеть с Substrate шифрованием"; "common.tx.details" = "Детали транзакции"; +"common.unknown" = "Неизвестно"; "staking.month.period.title" = "Eжемесячно"; "staking.year.period.title" = "Eжегодно"; "qr.scan.error.no.info" = "Не удается декодировать QR"; @@ -576,7 +576,6 @@ "account.create.details_v2_2_0" = "Не используйте буфер обмена или скриншоты на вашем мобильном устройстве, постарайтесь найти безопасные способы резервного копирования (например на бумагу)"; "crowdloan.list.section.format_v2_2_0" = "Выберите парачейны для внесения своих %@. Вы получите внесенные токены обратно, и если парачейн выиграет слот вы получите награду после окончания аукциона"; "crowdloan.empty.message_v2_2_0" = "Краудлоуны появятся здесь"; -"crowdloan.empty.message_v3_9_1" = "Информация о краудлоунах\nпоявится здесь, когда они начнутся"; "common.existential.warning.message_v2_2_0" = "Ваша учетная запись будет удалена из сети после операции, так как ваш баланс опустится ниже минимального"; "wallet.send.existential.warning_v2_2_0" = "Ваша учетная запись будет удалена из сети после перевода, так как опустит общий баланс ниже минимального"; "account.backup.mnemonic.title" = "Запишите фразу и храните её в надежном месте"; @@ -977,111 +976,107 @@ "yield.boost.task.not.found.message" = "Yield boost уже отключен для выбранного коллатора"; "common.not.available" = "N/A"; "wallet.account.locks.crowdloans" = "Краудлоуны"; +"common.unlock" = "Разблокировать"; +"gov.voters.empty" = "Список голосовавших появится здесь"; "tabbar.vote.title" = "Голосование"; -"tabbar.governance.title" = "Референдумы"; -"governance.referendums.status.preparing" = "подготовка"; -"governance.referendums.status.preparing.inqueue" = "в очереди"; -"governance.referendums.status.passing" = "прошел"; -"governance.referendums.status.not.passing" = "не прошел"; -"governance.referendums.status.approved" = "одобрен"; -"governance.referendums.status.rejected" = "отклонен"; -"governance.referendums.status.cancelled" = "отменен"; -"governance.referendums.status.timedOut" = "просрочен"; -"governance.referendums.status.killed" = "отменен"; -"governance.referendums.status.executed" = "выполнен"; - -"governance.referendums.time.deciding" = "Решение через %@"; -"governance.referendums.time.timeout" = "Истечет через %@"; -"governance.referendums.time.execute" = "Исполнение через %@"; -"governance.referendums.time.waiting.deposit" = "Ожидание депозита"; +"gov.common.amount.conviction.format" = "%@ × %@x"; +"gov.referendum.description.fallback" = "Только автор референдума может редактировать это описание и заголовок. Если у вас есть доступ к аккаунту автора, посетите Polkassembly и заполните информацию о вашем референдуме"; +"gov.voters.nay" = "Голоса \"против\""; +"gov.voters.aye" = "Голоса \"за\""; +"gov.support.curve" = "Кривая поддержки"; +"gov.approve.curve" = "Кривая одобрения"; +"gov.call.hash" = "Хэш вызова"; +"gov.electorate" = "Электорат"; +"gov.turnout" = "Явка"; +"gov.vote.threshold" = "Порог голосования"; +"gov.beneficiary" = "Получатель"; +"gov.deposit" = "Депозит"; +"gov.proposer" = "Автор"; +"common.too.long.preview" = "Слишком большая длина для просмотра"; +"gov.parameters.json" = "Параметры JSON"; +"common.requested.amount" = "Запрашиваемая сумма"; +"gov.details.voting.status" = "Статус голосования"; +"gov.full.details" = "Полная информация"; +"gov.vote" = "Голосовать"; +"gov.referendum.details.timeline.title" = "Временная шкала"; +"governance.nay" = "Против"; +"governance.aye" = "За"; +"gov.track.big.spender" = "Казна: большие траты"; +"gov.track.medium.spender" = "Казна: средние траты"; +"gov.track.small.spender" = "Казна: мелкие траты"; +"gov.track.big.tipper" = "Казна: большие чаевые"; +"gov.track.small.tipper" = "Казна: мелкие чаевые"; +"gov.track.referendum.killer" = "Управление: удаление"; +"gov.track.referendum.canceller" = "Управление: отмена"; +"gov.track.auction.admin" = "Краудлоуны"; +"gov.track.general.admin" = "Управление: регистратор"; +"gov.track.fellowship.admin" = "fellowship: управление"; +"gov.track.lease.admin" = "Управление: аренда"; +"gov.track.treasurer" = "Казна: любое"; +"gov.track.staking.admin" = "Стейкинг"; +"gov.track.whitelisted.caller" = "fellowship: белый список"; +"gov.track.root" = "основная повестка"; +"governance.referendums.time.execute" = "Выполнение через %@"; "governance.referendums.time.approve" = "Одобрение через %@"; -"governance.referendums.time.reject" = "Отмена через %@"; - +"governance.referendums.time.reject" = "Отклонение через %@"; +"governance.referendums.time.timeout" = "Тайм-аут через %@"; +"governance.referendums.time.waiting.deposit" = "Ожидание депозита"; +"governance.referendums.time.deciding" = "Начнёт решаться через %@"; +"governance.referendums.status.killed" = "Удалён"; +"governance.referendums.status.executed" = "Выполнен"; +"governance.referendums.status.preparing" = "Подготовка"; +"governance.referendums.status.rejected" = "Отклонён"; +"governance.referendums.status.not.passing" = "Не проходит"; +"governance.referendums.status.passing" = "Проходит"; +"governance.referendums.status.cancelled" = "Отменен"; +"governance.referendums.status.timedOut" = "Тайм-аут"; +"governance.referendums.status.approved" = "Одобрен"; +"governance.referendums.your.vote" = "Ваш голос: %@ голосов"; "governance.referendums.threshold" = "Порог: %@ из %@"; -"governance.referendums.your.vote" = "Ваше голосование: %@ голосов"; -"governance.referendums.active" = "Активные"; -"governance.referendums.completed" = "Завершённые"; - -"governance.ayes.format" = "За: %@"; +"gov.referendum.title.fallback" = "Референдум %@"; +"tabbar.governance.title" = "Демократия"; +"governance.to.pass.format" = "Для принятия: %@"; "governance.nays.format" = "Против: %@"; -"governance.to.pass.format" = "Для одобрения: %@"; -"governance.aye" = "За"; -"governance.nay" = "Против"; -"gov.track.root" = "Main agenda"; -"gov.track.auction.admin" = "Crowdloans"; -"gov.track.staking.admin" = "Staking"; -"gov.track.lease.admin" = "Governance: Lease"; -"gov.track.general.admin" = "Governance: Registrar"; -"gov.track.referendum.canceller" = "Governance: Canceller"; -"gov.track.referendum.killer" = "Governance: Killer"; -"gov.track.treasurer" = "Treasury: Any"; -"gov.track.small.tipper" = "Treasury: Small tips"; -"gov.track.big.tipper" = "Treasury: Big tips"; -"gov.track.small.spender" = "Treasury: Small Spend"; -"gov.track.medium.spender" = "Treasury: Medium Spend"; -"gov.track.big.spender" = "Treasury: Big Spend"; -"gov.track.whitelisted.caller" = "Fellowship: Whitelist"; -"gov.track.fellowship.admin" = "Fellowship: Admin"; -"gov.voters.aye" = "Голоса за"; -"gov.voters.nay" = "Голоса против"; +"governance.ayes.format" = "За: %@"; +"common.completed" = "Завершённые"; +"governance.referendums.active" = "На голосовании"; +"common.read.more" = "Подробнее"; "gov.common.votes.format" = "%@ голосов"; -"gov.common.amount.conviction.format" = "%@ × %@x"; -"gov.voters.empty" = "Список проголосовавших появится здесь"; -"gov.vote.conviction.title" = "Умножить голос, увеличивая период блокировки"; -"common.gov.lock" = "Блокировка в голосовании"; +"gov.timeline.created" = "Создан"; +"gov.vote.conviction.title" = "Умножьте количество голосов, увеличив период блокировки"; +"gov.vote.setup.title.format" = "Проголосовать за %@"; "common.locking.period" = "Период блокировки"; -"gov.vote.setup.hint" = "После окончания периода блокировки не забудьте забрать токены"; -"gov.vote.setup.title.format" = "Голосование за %@"; +"common.gov.lock" = "Заблокировано в демократии"; +"common. maximum" = "%@ максимум"; +"gov.vote.setup.hint" = "По истечении периода блокировки не забудьте разблокировать свои токены"; +"gov.revote" = "Переголосовать"; +"gov.max.votes.reached.message" = "Вы набрали максимальное количество голосов за трек: %@"; +"gov.max.votes.reached.title" = "Достигнуто максимальное количество голосов"; +"gov.already.delegating.votes.message" = "Вы делегируете голоса в треке данного референдума. Пожалуйста, либо попросите делегата проголосовать, либо удалите делегирование, чтобы иметь возможность голосовать напрямую."; +"gov.already.delegating.votes.title" = "Вы уже делегируете голоса"; +"gov.referendum.completed.message" = "Референдум завершен, голосовать больше нельзя"; +"gov.referendum.completed.title" = "Референдум завершен"; +"gov.not.enough.vote.tokens" = "У вас недостаточно токенов для голосования. Доступно для голосования: %@."; +"common.amount.too.big" = "Сумма слишком большая"; +"gov.reuse.all.locks" = "Уже заблокировано: %@"; +"gov.reuse.governance.locks" = "Уже в демократии: %@"; +"common.unlockable" = "Можно разблокировать"; +"gov.remains.locked.suffix" = "остаются заблокированными в %@"; +"governance.referendums.status.preparing.inqueue" = "в очереди"; "common.available.prefix" = "Доступно:"; -"common.maximum" = "%@ максимум"; -"gov.referendum.details.timeline.title" = "Статусы"; "gov.your.vote" = "Ваш голос"; -"common.amount.too.big" = "Сумма слишком большая"; -"gov.not.enough.vote.tokens" = "Извините, у Вас недостаточно токенов для голосования. Доступно токенов для голосования: %@"; -"gov.referendum.completed.title" = "Референдум завершен"; -"gov.referendum.completed.message" = "Голосование за референдум завершено"; -"gov.already.delegating.votes.title" = "Голоса делегированы"; -"gov.already.delegating.votes.message" = "Вы делегируете голоса в треке к которому относится выбранный референдум. Пожалуйста, либо попросите делегата проголосовать или отключите делегирование и голосуйте напрямую."; -"gov.max.votes.reached.title" = "Достигнуто максимальное количество голосов"; -"gov.max.votes.reached.message" = "Вы достигли максимального числа голосов %@ в треке"; -"gov.reuse.governance.locks" = "Заблокированные в голосовании: %@"; -"gov.reuse.all.locks" = "Все заблокированные: %@"; -"gov.vote" = "Голосовать"; -"gov.revote" = "Изменить голос"; -"gov.details.voting.status" = "Статус голосования"; -"common.requested.amount" = "Запрашиваемая сумма"; -"common.react.comment" = "Комментарии и реакции"; -"common.use.dapp" = "Использовать популярные вебсайты в Nova"; -"gov.timeline.created" = "Создано"; -"gov.timeline.voting.format" = "В процессе голосования: %@"; -"gov.timeline.voted.format" = "Голосование завершено: %@"; -"common.read.more" = "Читать дальше"; -"gov.referendum.title.fallback" = "Референдум %@"; -"gov.referendum.description.fallback" = "Только создатель референдума может редактировать заголовок и описание. Если Вы владеете аккаунтом создателя референдума, то заполните информацию о референдуме на Polkassembly"; -"gov.full.details" = "Техническая информация"; -"gov.proposer" = "Создатель"; -"gov.deposit" = "Депозит"; -"gov.beneficiary" = "Получатель"; -"gov.requested.amount" = "Запрашиваемая сумма"; -"gov.fulldetails.threshold" = "Порог голосования"; -"gov.fulldetails.turnout" = "Явка"; -"gov.fulldetails.electorate" = "Электорат"; -"gov.approve.curve" = "Кривая подтверждения"; -"gov.support.curve" = "Кривая поддержки"; -"gov.call.hash" = "Хэш вызова"; -"gov.parameters.json" = "Параметры вызова"; -"common.copy" = "Копировать"; -"common.too.long.preview" = "Слишком большой размер для просмотра"; +"common.use.dapp" = "Популярные вебсайты в Nova Wallet"; +"gov.timeline.voting.format" = "Голосование: %@"; +"gov.timeline.voted.format" = "Результат: %@"; "gov.linear.decreasing" = "Линейное убывание"; "gov.stepped.decreasing" = "Ступенчатое убывание"; "gov.reciprocal" = "Обратное линейное убывание"; -"gov.unknown" = "Неизвестно"; "gov.in.queue.counter" = "(%@ из %@)"; -"common.unlock" = "Разблокировать"; -"common.unlockable" = "Разблокируемые"; -"gov.remains.locked.suffix" = " остаются заблокированны в %@"; "gov.vote.treshold.function.simpleMajority" = "Простое большинство"; "gov.vote.treshold.function.superMajorityAgainst" = "Супербольшинство против"; "gov.vote.treshold.function.superMajorityApprove" = "Супербольшинство за"; "common.days.fraction.format" = "%@ дней"; "gov.empty.list" = "Информация о референдумах\nпоявится здесь, когда они начнутся"; +"common.copy" = "Копировать"; +"crowdloan.empty.message_v3_9_1" = "Информация о краудлоунах\nпоявится здесь, когда они начнутся"; +"common.error.no.data.retrieved_v3_9_1" = "Данные не получены"; \ No newline at end of file From 020619444d1bad7efd34a29078dc8ad5b03c0c7b Mon Sep 17 00:00:00 2001 From: Gulnaz <666lynx666@mail.ru> Date: Mon, 14 Nov 2022 11:54:29 +0400 Subject: [PATCH 212/229] fix links (#472) --- .../Governance/View/MarkdownViewContainer.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift b/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift index eeb1d3b688..69805b7a95 100644 --- a/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift +++ b/novawallet/Modules/Vote/Governance/View/MarkdownViewContainer.swift @@ -7,8 +7,7 @@ protocol MarkdownViewContainerDelegate: AnyObject { } final class MarkdownViewContainer: UIView, AnyCancellableCleaning { - private var textView: CDMarkdownTextView? - + private var textView: UITextView? private var model: MarkdownText? let preferredWidth: CGFloat @@ -55,22 +54,22 @@ final class MarkdownViewContainer: UIView, AnyCancellableCleaning { let textContainer = NSTextContainer(size: size) let layoutManager = CDMarkdownLayoutManager() + layoutManager.roundAllCorners = true layoutManager.addTextContainer(textContainer) + let textStorage = NSTextStorage() + textStorage.addLayoutManager(layoutManager) - let textView = CDMarkdownTextView( + let textView = UITextView( frame: .init(origin: .zero, size: size), - textContainer: textContainer, - layoutManager: layoutManager + textContainer: textContainer ) textView.delegate = self - textView.isEditable = false textView.isScrollEnabled = false textView.isSelectable = true textView.textContainerInset = .zero textView.textContainer.lineFragmentPadding = 0 - textView.roundAllCorners = true textView.backgroundColor = .clear From aca36c771f66ddf8a5fb407688cdcac562ea4e76 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 14 Nov 2022 14:29:47 +0500 Subject: [PATCH 213/229] refactoring --- .../Governance/Operation/Fetch/Gov1LocalMappingFactory.swift | 2 -- .../Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift index 261c33b9d4..a8ee3b4755 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift @@ -40,7 +40,6 @@ final class Gov1LocalMappingFactory { private func mapFinished( referendum: Democracy.FinishedStatus, index: Referenda.ReferendumIndex, - additionalInfo _: Gov1OperationFactory.AdditionalInfo, enactmentBlock: BlockNumber? ) -> ReferendumLocal { if referendum.approved { @@ -79,7 +78,6 @@ extension Gov1LocalMappingFactory { return mapFinished( referendum: status, index: index, - additionalInfo: additionalInfo, enactmentBlock: enactmentBlock ) case .unknown: diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift index a8b679ef0b..88285f16ca 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift @@ -19,7 +19,7 @@ final class Gov1OperationFactory { func encode(to encoder: Encoder) throws { let scaleEncoder = ScaleEncoder() - "democrac".data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } + Democracy.lockId.data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } try index.encode(scaleEncoder: scaleEncoder) let data = scaleEncoder.encode() From 07d598d5d9404a38d7695e40b614c9d5962354ce Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 14 Nov 2022 16:22:14 +0500 Subject: [PATCH 214/229] add new ledger apps --- novawallet/Common/Ledger/SupportedLedgerApps.swift | 5 ++++- novawallet/Common/Model/KnownChainIds.swift | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/novawallet/Common/Ledger/SupportedLedgerApps.swift b/novawallet/Common/Ledger/SupportedLedgerApps.swift index e6ed95098a..88c9ebae0f 100644 --- a/novawallet/Common/Ledger/SupportedLedgerApps.swift +++ b/novawallet/Common/Ledger/SupportedLedgerApps.swift @@ -19,7 +19,10 @@ extension SupportedLedgerApp { SupportedLedgerApp(chainId: KnowChainId.kusama, coin: 434, cla: 0x99, type: .substrate), SupportedLedgerApp(chainId: KnowChainId.statemint, coin: 354, cla: 0x96, type: .substrate), SupportedLedgerApp(chainId: KnowChainId.statemine, coin: 434, cla: 0x97, type: .substrate), - SupportedLedgerApp(chainId: KnowChainId.edgeware, coin: 523, cla: 0x94, type: .substrate) + SupportedLedgerApp(chainId: KnowChainId.edgeware, coin: 523, cla: 0x94, type: .substrate), + SupportedLedgerApp(chainId: KnowChainId.karura, coin: 686, cla: 0x9A, type: .substrate), + SupportedLedgerApp(chainId: KnowChainId.acala, coin: 787, cla: 0x9B, type: .substrate), + SupportedLedgerApp(chainId: KnowChainId.nodle, coin: 1003, cla: 0x98, type: .substrate) ] } diff --git a/novawallet/Common/Model/KnownChainIds.swift b/novawallet/Common/Model/KnownChainIds.swift index c78bb04cc3..00031049c3 100644 --- a/novawallet/Common/Model/KnownChainIds.swift +++ b/novawallet/Common/Model/KnownChainIds.swift @@ -7,4 +7,6 @@ enum KnowChainId { static let acala = "fc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c" static let statemint = "68d56f15f85d3136970ec16946040bc1752654e906147f7e43e9d539d7c3de2f" static let edgeware = "742a2ca70c2fda6cee4f8df98d64c4c670a052d9568058982dad9d5a7a135c5b" + static let karura = "baf5aabe40646d11f0ee8abbdc64f4a4b7674925cba08e4a05ff9ebed6e2126b" + static let nodle = "97da7ede98d7bad4e36b4d734b6055425a3be036da2a332ea5a7037656427a21" } From 69de49baefcf8b46230fb6d9eeee02d64e8f0bca Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 14 Nov 2022 16:28:19 +0500 Subject: [PATCH 215/229] fix apps ordering --- novawallet/Common/Ledger/SupportedLedgerApps.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/novawallet/Common/Ledger/SupportedLedgerApps.swift b/novawallet/Common/Ledger/SupportedLedgerApps.swift index 88c9ebae0f..c9cf2f7b95 100644 --- a/novawallet/Common/Ledger/SupportedLedgerApps.swift +++ b/novawallet/Common/Ledger/SupportedLedgerApps.swift @@ -19,10 +19,10 @@ extension SupportedLedgerApp { SupportedLedgerApp(chainId: KnowChainId.kusama, coin: 434, cla: 0x99, type: .substrate), SupportedLedgerApp(chainId: KnowChainId.statemint, coin: 354, cla: 0x96, type: .substrate), SupportedLedgerApp(chainId: KnowChainId.statemine, coin: 434, cla: 0x97, type: .substrate), - SupportedLedgerApp(chainId: KnowChainId.edgeware, coin: 523, cla: 0x94, type: .substrate), SupportedLedgerApp(chainId: KnowChainId.karura, coin: 686, cla: 0x9A, type: .substrate), SupportedLedgerApp(chainId: KnowChainId.acala, coin: 787, cla: 0x9B, type: .substrate), - SupportedLedgerApp(chainId: KnowChainId.nodle, coin: 1003, cla: 0x98, type: .substrate) + SupportedLedgerApp(chainId: KnowChainId.nodle, coin: 1003, cla: 0x98, type: .substrate), + SupportedLedgerApp(chainId: KnowChainId.edgeware, coin: 523, cla: 0x94, type: .substrate) ] } From dec7790349efcce28d6b9d93dde567bbb074e6d8 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 14 Nov 2022 17:30:42 +0500 Subject: [PATCH 216/229] fix presenter ref in crowdloan interactor --- .../CrowdloanListInteractor.swift | 62 +++++++++---------- .../CrowdloansListInteractor+Protocols.swift | 14 ++--- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift index bce4c0a980..d03e2be2a7 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloanListInteractor.swift @@ -3,7 +3,7 @@ import RobinHood import SoraFoundation final class CrowdloanListInteractor: RuntimeConstantFetching { - weak var presenter: CrowdloanListInteractorOutputProtocol! + weak var presenter: CrowdloanListInteractorOutputProtocol? let selectedMetaAccount: MetaAccountModel let crowdloanState: CrowdloanSharedState @@ -108,12 +108,12 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { clearOnchainContributionRequest(true) guard !crowdloans.isEmpty else { - presenter.didReceiveContributions(result: .success([:])) + presenter?.didReceiveContributions(result: .success([:])) return } guard let accountResponse = selectedMetaAccount.fetch(for: chain.accountRequest()) else { - presenter.didReceiveContributions(result: .success([:])) + presenter?.didReceiveContributions(result: .success([:])) return } @@ -143,14 +143,14 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { do { let contributions = try contributionsOperation.extractNoCancellableResultData().toDict() - self?.presenter.didReceiveContributions(result: .success(contributions)) + self?.presenter?.didReceiveContributions(result: .success(contributions)) } catch { if let encodingError = error as? StorageKeyEncodingOperationError, encodingError == .invalidStoragePath { - self?.presenter.didReceiveContributions(result: .success([:])) + self?.presenter?.didReceiveContributions(result: .success([:])) } else { - self?.presenter.didReceiveContributions(result: .failure(error)) + self?.presenter?.didReceiveContributions(result: .failure(error)) } } } @@ -179,7 +179,7 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { clearLeaseInfoRequest(true) guard !crowdloans.isEmpty else { - presenter.didReceiveLeaseInfo(result: .success([:])) + presenter?.didReceiveLeaseInfo(result: .success([:])) return } @@ -199,14 +199,14 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { do { let leaseInfo = try queryWrapper.targetOperation.extractNoCancellableResultData().toMap() - self?.presenter.didReceiveLeaseInfo(result: .success(leaseInfo)) + self?.presenter?.didReceiveLeaseInfo(result: .success(leaseInfo)) } catch { if let encodingError = error as? StorageKeyEncodingOperationError, encodingError == .invalidStoragePath { - self?.presenter.didReceiveLeaseInfo(result: .success([:])) + self?.presenter?.didReceiveLeaseInfo(result: .success([:])) } else { - self?.presenter.didReceiveLeaseInfo(result: .failure(error)) + self?.presenter?.didReceiveLeaseInfo(result: .failure(error)) } } } @@ -219,16 +219,16 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { } private func notifyCrowdolansFetchWithError(error: Error) { - presenter.didReceiveCrowdloans(result: .failure(error)) - presenter.didReceiveContributions(result: .failure(error)) - presenter.didReceiveLeaseInfo(result: .failure(error)) + presenter?.didReceiveCrowdloans(result: .failure(error)) + presenter?.didReceiveContributions(result: .failure(error)) + presenter?.didReceiveLeaseInfo(result: .failure(error)) } private func subscribeToDisplayInfo(for chain: ChainModel) { displayInfoProvider = nil guard let crowdloanUrl = chain.externalApi?.crowdloans?.url else { - presenter.didReceiveDisplayInfo(result: .success([:])) + presenter?.didReceiveDisplayInfo(result: .success([:])) return } @@ -236,12 +236,12 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { let updateClosure: ([DataProviderChange]) -> Void = { [weak self] changes in if let result = changes.reduceToLastChange() { - self?.presenter.didReceiveDisplayInfo(result: .success(result.toMap())) + self?.presenter?.didReceiveDisplayInfo(result: .success(result.toMap())) } } let failureClosure: (Error) -> Void = { [weak self] error in - self?.presenter.didReceiveDisplayInfo(result: .failure(error)) + self?.presenter?.didReceiveDisplayInfo(result: .failure(error)) } let options = DataProviderObserverOptions(alwaysNotifyOnRefresh: true, waitsInProgressSyncOnAdd: false) @@ -266,9 +266,9 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { private func provideConstants(for chain: ChainModel) { guard let runtimeService = chainRegistry.getRuntimeProvider(for: chain.chainId) else { let error = ChainRegistryError.runtimeMetadaUnavailable - presenter.didReceiveBlockDuration(result: .failure(error)) - presenter.didReceiveLeasingPeriod(result: .failure(error)) - presenter.didReceiveLeasingOffset(result: .failure(error)) + presenter?.didReceiveBlockDuration(result: .failure(error)) + presenter?.didReceiveLeasingPeriod(result: .failure(error)) + presenter?.didReceiveLeasingOffset(result: .failure(error)) return } @@ -277,7 +277,7 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { runtimeCodingService: runtimeService, operationManager: operationManager ) { [weak self] (result: Result) in - self?.presenter.didReceiveBlockDuration(result: result) + self?.presenter?.didReceiveBlockDuration(result: result) } fetchConstant( @@ -285,7 +285,7 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { runtimeCodingService: runtimeService, operationManager: operationManager ) { [weak self] (result: Result) in - self?.presenter.didReceiveLeasingPeriod(result: result) + self?.presenter?.didReceiveLeasingPeriod(result: result) } fetchConstant( @@ -293,7 +293,7 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { runtimeCodingService: runtimeService, operationManager: operationManager ) { [weak self] (result: Result) in - self?.presenter.didReceiveLeasingOffset(result: result) + self?.presenter?.didReceiveLeasingOffset(result: result) } } @@ -305,21 +305,21 @@ final class CrowdloanListInteractor: RuntimeConstantFetching { if let priceId = chain.utilityAsset()?.priceId { priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) } else { - presenter.didReceivePriceData(result: nil) + presenter?.didReceivePriceData(result: nil) } } } extension CrowdloanListInteractor { func setup(with accountId: AccountId?, chain: ChainModel) { - presenter.didReceiveSelectedChain(result: .success(chain)) + presenter?.didReceiveSelectedChain(result: .success(chain)) if let accountId = accountId { subscribeToAccountInfo(for: accountId, chain: chain) subscribeToExternalContributions(for: accountId, chain: chain) } else { - presenter.didReceiveAccountInfo(result: .success(nil)) - presenter.didReceiveExternalContributions(result: .success([])) + presenter?.didReceiveAccountInfo(result: .success(nil)) + presenter?.didReceiveExternalContributions(result: .success([])) } subscribePrice() @@ -429,14 +429,14 @@ extension CrowdloanListInteractor { connection: connection, runtimeService: runtimeService ) - self?.presenter.didReceiveCrowdloans(result: .success(crowdloans)) + self?.presenter?.didReceiveCrowdloans(result: .success(crowdloans)) } catch { if let encodingError = error as? StorageKeyEncodingOperationError, encodingError == .invalidStoragePath { - self?.presenter.didReceiveCrowdloans(result: .success([])) - self?.presenter.didReceiveContributions(result: .success([:])) - self?.presenter.didReceiveLeaseInfo(result: .success([:])) + self?.presenter?.didReceiveCrowdloans(result: .success([])) + self?.presenter?.didReceiveContributions(result: .success([:])) + self?.presenter?.didReceiveLeaseInfo(result: .success([:])) } else { self?.notifyCrowdolansFetchWithError(error: error) } @@ -450,7 +450,7 @@ extension CrowdloanListInteractor { extension CrowdloanListInteractor: PriceLocalStorageSubscriber, PriceLocalSubscriptionHandler { func handlePrice(result: Result, priceId _: AssetModel.PriceId) { - presenter.didReceivePriceData(result: result) + presenter?.didReceivePriceData(result: result) } } diff --git a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift index f1938bddec..04b401b599 100644 --- a/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift +++ b/novawallet/Modules/Vote/Crowdloan/CrowdloanList/CrowdloansListInteractor+Protocols.swift @@ -7,7 +7,7 @@ extension CrowdloanListInteractor: CrowdloanListInteractorInputProtocol { applicationHandler.delegate = self guard let chain = crowdloanState.settings.value else { - presenter.didReceiveSelectedChain(result: .failure( + presenter?.didReceiveSelectedChain(result: .failure( PersistentValueSettingsError.missingValue )) return @@ -34,7 +34,7 @@ extension CrowdloanListInteractor: CrowdloanListInteractorInputProtocol { func refresh() { guard let chain = crowdloanState.settings.value else { - presenter.didReceiveSelectedChain(result: .failure( + presenter?.didReceiveSelectedChain(result: .failure( PersistentValueSettingsError.missingValue )) return @@ -52,7 +52,7 @@ extension CrowdloanListInteractor: CrowdloanListInteractorInputProtocol { case .success: self?.handleSelectionChange(to: chainModel) case let .failure(error): - self?.presenter.didReceiveSelectedChain(result: .failure(error)) + self?.presenter?.didReceiveSelectedChain(result: .failure(error)) } } } @@ -84,7 +84,7 @@ extension CrowdloanListInteractor: CrowdloanLocalStorageSubscriber, CrowdloanLoc func handleBlockNumber(result: Result, chainId: ChainModel.Id) { if let chain = crowdloanState.settings.value, chain.chainId == chainId { provideCrowdloans(for: chain) - presenter.didReceiveBlockNumber(result: result) + presenter?.didReceiveBlockNumber(result: result) } } } @@ -97,7 +97,7 @@ extension CrowdloanListInteractor: WalletLocalStorageSubscriber, WalletLocalSubs ) { if let chain = crowdloanState.settings.value, chain.chainId == chainId { logger?.debug("Did receive balance for accountId: \(accountId.toHex()))") - presenter.didReceiveAccountInfo(result: result) + presenter?.didReceiveAccountInfo(result: result) } } } @@ -114,9 +114,9 @@ extension CrowdloanListInteractor: CrowdloanOffchainSubscriber, CrowdloanOffchai ) { switch result { case let .success(maybeContributions): - presenter.didReceiveExternalContributions(result: .success(maybeContributions ?? [])) + presenter?.didReceiveExternalContributions(result: .success(maybeContributions ?? [])) case let .failure(error): - presenter.didReceiveExternalContributions(result: .failure(error)) + presenter?.didReceiveExternalContributions(result: .failure(error)) } } } From c3bc300e8917b052d9f9f15108783d5394e324cb Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 14 Nov 2022 17:40:07 +0500 Subject: [PATCH 217/229] prevent safari from crashing on url tap --- novawallet/Common/Protocols/WebPresentable.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/novawallet/Common/Protocols/WebPresentable.swift b/novawallet/Common/Protocols/WebPresentable.swift index 40f7de5cbf..8b63a764be 100644 --- a/novawallet/Common/Protocols/WebPresentable.swift +++ b/novawallet/Common/Protocols/WebPresentable.swift @@ -13,6 +13,11 @@ protocol WebPresentable: AnyObject { extension WebPresentable { func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { + let supportedSafariScheme = ["https", "http"] + guard let scheme = url.scheme, supportedSafariScheme.contains(scheme) else { + return + } + let webController = WebViewFactory.createWebViewController(for: url, style: style) view.controller.present(webController, animated: true, completion: nil) } From 477b0d6bbb7476177782db8cac6b28b9dda175c8 Mon Sep 17 00:00:00 2001 From: ERussel Date: Mon, 14 Nov 2022 23:08:55 +0500 Subject: [PATCH 218/229] fix race condition fix for chain storage item update --- .../DataProvider/Sources/StorageProviderSource.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/novawallet/Common/DataProvider/Sources/StorageProviderSource.swift b/novawallet/Common/DataProvider/Sources/StorageProviderSource.swift index 945c62fc64..e3ffe1b259 100644 --- a/novawallet/Common/DataProvider/Sources/StorageProviderSource.swift +++ b/novawallet/Common/DataProvider/Sources/StorageProviderSource.swift @@ -52,15 +52,18 @@ final class StorageProviderSource: DataProviderSourceP // MARK: Private private func replaceAndNotifyIfNeeded(_ newItem: ChainStorageItem?) { - let newValue = LastSeen.received(value: newItem) - if newValue != lastSeenResult || lastSeenError != nil { - lock.lock() + lock.lock() + let newValue = LastSeen.received(value: newItem) + let shouldUpdate = newValue != lastSeenResult || lastSeenError != nil + if shouldUpdate { lastSeenError = nil lastSeenResult = newValue + } - lock.unlock() + lock.unlock() + if shouldUpdate { trigger.delegate?.didTrigger() } } From c8a86e990507c27ff35135198f612bc28e4f64f9 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 15 Nov 2022 09:57:14 +0500 Subject: [PATCH 219/229] fix AccountInfo.available --- novawallet/Common/Substrate/Types/AccountInfo.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Common/Substrate/Types/AccountInfo.swift b/novawallet/Common/Substrate/Types/AccountInfo.swift index e8f9ebb894..b8df2f41cd 100644 --- a/novawallet/Common/Substrate/Types/AccountInfo.swift +++ b/novawallet/Common/Substrate/Types/AccountInfo.swift @@ -18,5 +18,5 @@ extension AccountData { var total: BigUInt { free + reserved } var frozen: BigUInt { reserved + locked } var locked: BigUInt { max(miscFrozen, feeFrozen) } - var available: BigUInt { free - locked } + var available: BigUInt { free > locked ? free - locked : 0 } } From 8a9eb9e6ea6bc03672984e7ac70552a1518b860b Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 22 Nov 2022 00:18:03 +0500 Subject: [PATCH 220/229] fix proposal parsing --- .../Types/Democracy/DemocracyReferendum.swift | 16 +++++++++++++++- .../Vote/Governance/Model/ReferendumLocal.swift | 2 +- .../Fetch/Gov1LocalMappingFactory.swift | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift index a33590a3fa..5983ebf273 100644 --- a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift @@ -3,6 +3,8 @@ import SubstrateSdk import BigInt extension Democracy { + typealias Proposal = SupportPallet.Bounded> + struct Tally: Decodable { /// The number of aye votes, expressed in terms of post-conviction lock-vote. @StringCodable var ayes: BigUInt @@ -17,9 +19,21 @@ extension Democracy { struct OngoingStatus: Decodable { @StringCodable var end: BlockNumber @StringCodable var delay: BlockNumber - @SupportPallet.HashOrBoundedCallWrapper var proposalHash: SupportPallet.Bounded> + + // + let proposalHash: BytesCodable? + let proposal: Proposal? + let threshold: Democracy.VoteThreshold let tally: Tally + + var universalProposal: Proposal? { + if let proposalHash = proposalHash { + return .legacy(hash: proposalHash.wrappedValue) + } else { + return proposal + } + } } struct FinishedStatus: Decodable { diff --git a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift index 0893588686..e7541a9737 100644 --- a/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift +++ b/novawallet/Modules/Vote/Governance/Model/ReferendumLocal.swift @@ -154,7 +154,7 @@ enum ReferendumStateLocal { struct Deciding { let track: GovernanceTrackLocal - let proposal: SupportPallet.Bounded> + let proposal: Democracy.Proposal? let voting: Voting let submitted: BlockNumber let since: BlockNumber diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift index a8ee3b4755..8171be6d85 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1LocalMappingFactory.swift @@ -25,7 +25,7 @@ final class Gov1LocalMappingFactory { let state = ReferendumStateLocal.Deciding( track: track, - proposal: referendum.proposalHash, + proposal: referendum.universalProposal, voting: .threshold(voting), submitted: submitted, since: submitted, From afb4b0851fa728cda1bb71a9044e688b84cb271b Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 22 Nov 2022 16:36:22 +0500 Subject: [PATCH 221/229] support different scheduler keys --- novawallet.xcodeproj/project.pbxproj | 12 ++ .../Extension/Foundation/Data+Fill.swift | 13 +++ .../CodingFactory+TypeCheck.swift | 12 ++ .../StorageEntryMetadata+TypeCheck.swift | 26 +++++ .../RuntimeCoderFactory.swift | 12 ++ .../Fetch/Gov1OperationFactory.swift | 105 ++++++++++++++++-- 6 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 novawallet/Common/Extension/Foundation/Data+Fill.swift create mode 100644 novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift create mode 100644 novawallet/Common/Extension/SubstrateSdk/StorageEntryMetadata+TypeCheck.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 66275470a8..3f10a1315f 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -352,6 +352,8 @@ 8401F24F24E524900081D8F8 /* String+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8401F24E24E524900081D8F8 /* String+Helpers.swift */; }; 8402CC9C275B92AC00E5BF30 /* ControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8402CC9B275B92AC00E5BF30 /* ControlView.swift */; }; 8402CC9E275B946100E5BF30 /* DAppItemViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8402CC9D275B946100E5BF30 /* DAppItemViewCell.swift */; }; + 840302DE292CE3EA0013F356 /* StorageEntryMetadata+TypeCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840302DD292CE3EA0013F356 /* StorageEntryMetadata+TypeCheck.swift */; }; + 840302E0292CE4030013F356 /* CodingFactory+TypeCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840302DF292CE4030013F356 /* CodingFactory+TypeCheck.swift */; }; 84031C17263EC95C008FD9D4 /* SetPayeeCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84031C16263EC95C008FD9D4 /* SetPayeeCall.swift */; }; 84033055290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84033054290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift */; }; 84033057290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84033056290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift */; }; @@ -1986,6 +1988,7 @@ 84D8F16D24D82C7E00AF43E9 /* ModalPickerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8F16C24D82C7E00AF43E9 /* ModalPickerConfiguration.swift */; }; 84D8F16F24D8451F00AF43E9 /* CryptoType+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8F16E24D8451F00AF43E9 /* CryptoType+ViewModel.swift */; }; 84D8F17124D856D300AF43E9 /* SNAddressType+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D8F17024D856D300AF43E9 /* SNAddressType+ViewModel.swift */; }; + 84D911AA292C923D0032EF33 /* Data+Fill.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D911A9292C923D0032EF33 /* Data+Fill.swift */; }; 84D97EC82520D32000F07405 /* PolkadotIcon+Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D97EC72520D32000F07405 /* PolkadotIcon+Image.swift */; }; 84D97ECF2521CA2F00F07405 /* WalletBaseTokenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D97ECE2521CA2F00F07405 /* WalletBaseTokenView.swift */; }; 84D97ED12521CA5200F07405 /* WalletTokenView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84D97ED02521CA5200F07405 /* WalletTokenView.xib */; }; @@ -3337,6 +3340,8 @@ 8401F24E24E524900081D8F8 /* String+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Helpers.swift"; sourceTree = ""; }; 8402CC9B275B92AC00E5BF30 /* ControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlView.swift; sourceTree = ""; }; 8402CC9D275B946100E5BF30 /* DAppItemViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppItemViewCell.swift; sourceTree = ""; }; + 840302DD292CE3EA0013F356 /* StorageEntryMetadata+TypeCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StorageEntryMetadata+TypeCheck.swift"; sourceTree = ""; }; + 840302DF292CE4030013F356 /* CodingFactory+TypeCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CodingFactory+TypeCheck.swift"; sourceTree = ""; }; 84031C16263EC95C008FD9D4 /* SetPayeeCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetPayeeCall.swift; sourceTree = ""; }; 84033054290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsUnlocksViewModel.swift; sourceTree = ""; }; 84033056290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsUnlocksTableViewCell.swift; sourceTree = ""; }; @@ -4989,6 +4994,7 @@ 84D8F16C24D82C7E00AF43E9 /* ModalPickerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalPickerConfiguration.swift; sourceTree = ""; }; 84D8F16E24D8451F00AF43E9 /* CryptoType+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CryptoType+ViewModel.swift"; sourceTree = ""; }; 84D8F17024D856D300AF43E9 /* SNAddressType+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SNAddressType+ViewModel.swift"; sourceTree = ""; }; + 84D911A9292C923D0032EF33 /* Data+Fill.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Fill.swift"; sourceTree = ""; }; 84D97EC72520D32000F07405 /* PolkadotIcon+Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PolkadotIcon+Image.swift"; sourceTree = ""; }; 84D97ECE2521CA2F00F07405 /* WalletBaseTokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletBaseTokenView.swift; sourceTree = ""; }; 84D97ED02521CA5200F07405 /* WalletTokenView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WalletTokenView.xib; sourceTree = ""; }; @@ -7716,6 +7722,8 @@ 8493D0E026FF4F5000A28008 /* ScaleCoder+Extension.swift */, 84D2F19C2771E5610040C680 /* ExtrinsicBuilder+Signing.swift */, 8499FEC727BF73F400712589 /* StorageKeyFactory+Size.swift */, + 840302DD292CE3EA0013F356 /* StorageEntryMetadata+TypeCheck.swift */, + 840302DF292CE4030013F356 /* CodingFactory+TypeCheck.swift */, ); path = SubstrateSdk; sourceTree = ""; @@ -9756,6 +9764,7 @@ 84D9C8F228ADA42F007FB23B /* Data+Chunk.swift */, 880855EC28D062A9004255E7 /* Array+AddOrReplace.swift */, 88BB219F28D34C660019C6B4 /* DataProviderChange+Identifier.swift */, + 84D911A9292C923D0032EF33 /* Data+Fill.swift */, ); path = Foundation; sourceTree = ""; @@ -15841,6 +15850,7 @@ 849AFEB326DADC1300B65924 /* SubqueryHistory.swift in Sources */, 846A683027469BD500D1A47A /* CrowdloanOffchainProviderFactory.swift in Sources */, 84C11F1C2842B869007F7C05 /* ParaStkCollatorFiltersViewModel.swift in Sources */, + 840302E0292CE4030013F356 /* CodingFactory+TypeCheck.swift in Sources */, AEE5FB1626457AA9002B8FDC /* StakingRewardDestSetupPresenter.swift in Sources */, 88107D5F290133F8001AB0B0 /* RoundedView+Styles.swift in Sources */, 8468B86E24F63D1400B76BC6 /* AddAccount+OnboardingMainWireframe.swift in Sources */, @@ -15961,6 +15971,7 @@ 8428768524AE046300D91AD8 /* LanguageSelectionProtocols.swift in Sources */, 2A90206E273E6CA200F2D584 /* NetworkFeeConfirmView+Protocol.swift in Sources */, AEA0C8A4267B6B1900F9666F /* SelectedValidatorListProtocols.swift in Sources */, + 84D911AA292C923D0032EF33 /* Data+Fill.swift in Sources */, F4B39C4E27326E8400BB6E10 /* AcalaContributionSetupViewController.swift in Sources */, 84E63C1728FFC69A0093534A /* DiscreteGradientSlider.swift in Sources */, 84EC2D18276B9DBC009B0BE1 /* PolkadotExtensionAccount.swift in Sources */, @@ -16326,6 +16337,7 @@ 843461CF26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift in Sources */, 882A5CED28AFCE3600D0D798 /* ReturnInIntervalsViewModel.swift in Sources */, 88C7165428C894510015D1E9 /* CollectionViewDelegate.swift in Sources */, + 840302DE292CE3EA0013F356 /* StorageEntryMetadata+TypeCheck.swift in Sources */, F458D3982642911B0055CB75 /* ControllerAccountViewModel.swift in Sources */, 84DAC198268D3DD9002D0DF4 /* SNAddressType.swift in Sources */, 84AC0B6A28C0D8CE00FA5B5D /* NoLedgerSupportCommand.swift in Sources */, diff --git a/novawallet/Common/Extension/Foundation/Data+Fill.swift b/novawallet/Common/Extension/Foundation/Data+Fill.swift new file mode 100644 index 0000000000..4e338a02a3 --- /dev/null +++ b/novawallet/Common/Extension/Foundation/Data+Fill.swift @@ -0,0 +1,13 @@ +import Foundation + +extension Data { + func fillRightWithZeros(ifLess size: Int) -> Data { + guard count < size else { + return self + } + + let neededZeros = size - count + + return self + Data(repeating: 0, count: neededZeros) + } +} diff --git a/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift b/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift new file mode 100644 index 0000000000..7a743e700e --- /dev/null +++ b/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift @@ -0,0 +1,12 @@ +import Foundation +import SubstrateSdk + +extension RuntimeCoderFactoryProtocol { + func isBytesArrayType(_ type: String) -> Bool { + guard let vectorNode = getTypeNode(for: type) as? VectorNode else { + return false + } + + return getTypeNode(for: vectorNode.underlying.typeName) is U8Node + } +} diff --git a/novawallet/Common/Extension/SubstrateSdk/StorageEntryMetadata+TypeCheck.swift b/novawallet/Common/Extension/SubstrateSdk/StorageEntryMetadata+TypeCheck.swift new file mode 100644 index 0000000000..a6d86d9d1d --- /dev/null +++ b/novawallet/Common/Extension/SubstrateSdk/StorageEntryMetadata+TypeCheck.swift @@ -0,0 +1,26 @@ +import Foundation +import SubstrateSdk + +extension RuntimeMetadataProtocol { + func isMapStorageKeyOfType(_ storagePath: StorageCodingPath, closure: (String) -> Bool) -> Bool { + guard let storage = getStorageMetadata( + in: storagePath.moduleName, + storageName: storagePath.itemName + ) else { + return false + } + + return storage.isMapKeyOfType(closure) + } +} + +extension StorageEntryMetadata { + func isMapKeyOfType(_ closure: (String) -> Bool) -> Bool { + switch type { + case let .map(entry): + return closure(entry.key) + default: + return false + } + } +} diff --git a/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift b/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift index da05d2f90f..76c1be4d76 100644 --- a/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift +++ b/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift @@ -9,7 +9,9 @@ protocol RuntimeCoderFactoryProtocol { func createEncoder() -> DynamicScaleEncoding func createDecoder(from data: Data) throws -> DynamicScaleDecoding func createRuntimeJsonContext() -> RuntimeJsonContext + func hasType(for name: String) -> Bool + func getTypeNode(for name: String) -> Node? } final class RuntimeCoderFactory: RuntimeCoderFactoryProtocol { @@ -57,4 +59,14 @@ final class RuntimeCoderFactory: RuntimeCoderFactoryProtocol { func hasType(for name: String) -> Bool { catalog.node(for: name, version: UInt64(specVersion)) != nil } + + func getTypeNode(for name: String) -> Node? { + let node = catalog.node(for: name, version: UInt64(specVersion)) + + if let aliasNode = node as? AliasNode { + return getTypeNode(for: aliasNode.underlyingTypeName) + } else { + return node + } + } } diff --git a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift index 88285f16ca..59ea1464d4 100644 --- a/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift +++ b/novawallet/Modules/Vote/Governance/Operation/Fetch/Gov1OperationFactory.swift @@ -14,18 +14,58 @@ final class Gov1OperationFactory { let block: BlockNumber } + typealias SchedulerKeysClosure = () throws -> [SchedulerTaskName] + struct SchedulerTaskName: Encodable { + static let taskNameSize = 32 + + enum EncodingScheme { + case legacy + case migrating + case actual + } + let index: Referenda.ReferendumIndex + let encodingScheme: EncodingScheme + + init(index: Referenda.ReferendumIndex, encodingScheme: EncodingScheme = .actual) { + self.index = index + self.encodingScheme = encodingScheme + } func encode(to encoder: Encoder) throws { let scaleEncoder = ScaleEncoder() Democracy.lockId.data(using: .utf8).map { scaleEncoder.appendRaw(data: $0) } try index.encode(scaleEncoder: scaleEncoder) - let data = scaleEncoder.encode() + let encodedData = scaleEncoder.encode() + let keyData: Data + + switch encodingScheme { + case .legacy: + keyData = encodedData + case .migrating: + keyData = try encodedData.blake2b32() + case .actual: + keyData = try hash(data: encodedData, ifExceeds: Self.taskNameSize) + } var container = encoder.singleValueContainer() - try container.encode(BytesCodable(wrappedValue: data)) + try container.encode(BytesCodable(wrappedValue: keyData)) + } + + private func hash(data: Data, ifExceeds size: Int) throws -> Data { + if data.count <= size { + return data.fillRightWithZeros(ifLess: size) + } else { + let hashedData = try data.blake2b32() + + if hashedData.count <= size { + return hashedData.fillRightWithZeros(ifLess: size) + } else { + return hashedData.prefix(size) + } + } } } @@ -37,20 +77,46 @@ final class Gov1OperationFactory { self.operationQueue = operationQueue } - func createEnacmentTimeFetchWrapper( + private func prepareSchedulerKeysClosure( dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: Democracy.ReferendumInfo]>, - connection: JSONRPCEngine, - runtimeProvider: RuntimeProviderProtocol, - blockHash: Data? - ) -> CompoundOperationWrapper<[ReferendumIdLocal: BlockNumber]> { - let keysClosure: () throws -> [SchedulerTaskName] = { + codingFactoryOperation: BaseOperation, + storagePath: StorageCodingPath + ) -> SchedulerKeysClosure { + { let referendums = try referendumOperation.extractNoCancellableResultData() - return referendums.compactMap { keyValue in + let codingFactory = try codingFactoryOperation.extractNoCancellableResultData() + let metadata = codingFactory.metadata + + let shouldUseLegacyEncoding: Bool = metadata.isMapStorageKeyOfType(storagePath) { key in + // legacy keys are composed of unbounded byte array + codingFactory.isBytesArrayType(key) + } + + let keys: [[SchedulerTaskName]] = referendums.compactMap { keyValue in switch keyValue.value { case let .finished(status): if status.approved { - return SchedulerTaskName(index: keyValue.key.referendumIndex) + if shouldUseLegacyEncoding { + let key = SchedulerTaskName( + index: keyValue.key.referendumIndex, + encodingScheme: .legacy + ) + + return [key] + } else { + let key1 = SchedulerTaskName( + index: keyValue.key.referendumIndex, + encodingScheme: .actual + ) + + let key2 = SchedulerTaskName( + index: keyValue.key.referendumIndex, + encodingScheme: .migrating + ) + + return [key1, key2] + } } else { return nil } @@ -58,16 +124,33 @@ final class Gov1OperationFactory { return nil } } + + return keys.flatMap { $0 } } + } + func createEnacmentTimeFetchWrapper( + dependingOn referendumOperation: BaseOperation<[ReferendumIndexKey: Democracy.ReferendumInfo]>, + connection: JSONRPCEngine, + runtimeProvider: RuntimeProviderProtocol, + blockHash: Data? + ) -> CompoundOperationWrapper<[ReferendumIdLocal: BlockNumber]> { let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + let storagePath = OnChainScheduler.lookupTaskPath + + let keysClosure = prepareSchedulerKeysClosure( + dependingOn: referendumOperation, + codingFactoryOperation: codingFactoryOperation, + storagePath: storagePath + ) + let enactmentWrapper: CompoundOperationWrapper<[StorageResponse]> = requestFactory.queryItems( engine: connection, keyParams: keysClosure, factory: { try codingFactoryOperation.extractNoCancellableResultData() }, - storagePath: OnChainScheduler.lookupTaskPath, + storagePath: storagePath, at: blockHash ) From b85c7cda30812033eea368a7ccc2bb2330686aeb Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 22 Nov 2022 16:48:41 +0500 Subject: [PATCH 222/229] fix fetching type --- .../ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift b/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift index 76c1be4d76..c11d0566a2 100644 --- a/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift +++ b/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift @@ -65,6 +65,8 @@ final class RuntimeCoderFactory: RuntimeCoderFactoryProtocol { if let aliasNode = node as? AliasNode { return getTypeNode(for: aliasNode.underlyingTypeName) + } else if let proxyNode = node as? ProxyNode { + return getTypeNode(for: proxyNode.typeName) } else { return node } From f4c172676435662703b5e248a90d8fa82d638c03 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 23 Nov 2022 00:25:06 +0500 Subject: [PATCH 223/229] save governance type with chain --- novawallet.xcodeproj/project.pbxproj | 36 ++++ .../GovMetadataLocalSubscriptionFactory.swift | 18 +- .../GovMetadataLocalStorageHandler.swift | 8 +- .../GovMetadataLocalStorageSubscriber.swift | 20 +- .../Common/Extension/SettingsExtension.swift | 22 +++ .../Storage/GovernanceChainSettings.swift | 74 +++++-- .../ChainBalanceViewModelFactory.swift | 24 ++- .../AssetSelectionBasePresenter.swift | 187 ++++++++++++++++++ .../AssetSelectionBaseProtocols.swift | 3 + .../AssetSelectionPresenter.swift | 178 ++--------------- .../AssetSelectionProtocols.swift | 2 +- .../GovernanceAssetSelectionPresenter.swift | 93 +++++++++ .../GovernanceAssetSelectionProtocols.swift | 12 ++ .../GovernanceAssetSelectionViewFactory.swift | 62 ++++++ .../GovernanceAssetSelectionWireframe.swift | 17 ++ .../GovernanceUnlockConfirmViewFactory.swift | 25 ++- .../GovernanceUnlockSetupViewFactory.swift | 4 +- .../Model/GovernanceSharedState.swift | 44 +++-- .../Governance/Model/GovernanceType.swift | 30 +++ .../ReferendumDetailsInteractor.swift | 14 +- .../ReferendumDetailsViewFactory.swift | 13 +- .../ReferendumFullDetailsViewFactory.swift | 2 +- .../ReferendumVoteConfirmViewFactory.swift | 23 ++- .../ReferendumVoteSetupViewFactory.swift | 21 +- .../ReferendumVotersViewFactory.swift | 4 +- .../Referendums/ReferendumsInteractor.swift | 68 +++---- .../Referendums/ReferendumsPresenter.swift | 48 +++-- .../Referendums/ReferendumsProtocols.swift | 9 +- .../Referendums/ReferendumsWireframe.swift | 18 +- 29 files changed, 756 insertions(+), 323 deletions(-) create mode 100644 novawallet/Modules/AssetSelection/AssetSelectionBasePresenter.swift create mode 100644 novawallet/Modules/AssetSelection/AssetSelectionBaseProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionPresenter.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionProtocols.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionViewFactory.swift create mode 100644 novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionWireframe.swift create mode 100644 novawallet/Modules/Vote/Governance/Model/GovernanceType.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 3f10a1315f..82d6d3382f 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -354,6 +354,8 @@ 8402CC9E275B946100E5BF30 /* DAppItemViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8402CC9D275B946100E5BF30 /* DAppItemViewCell.swift */; }; 840302DE292CE3EA0013F356 /* StorageEntryMetadata+TypeCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840302DD292CE3EA0013F356 /* StorageEntryMetadata+TypeCheck.swift */; }; 840302E0292CE4030013F356 /* CodingFactory+TypeCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840302DF292CE4030013F356 /* CodingFactory+TypeCheck.swift */; }; + 840302E4292CFCF90013F356 /* AssetSelectionBasePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840302E3292CFCF90013F356 /* AssetSelectionBasePresenter.swift */; }; + 840302E8292D00380013F356 /* GovernanceAssetSelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840302E7292D00380013F356 /* GovernanceAssetSelectionPresenter.swift */; }; 84031C17263EC95C008FD9D4 /* SetPayeeCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84031C16263EC95C008FD9D4 /* SetPayeeCall.swift */; }; 84033055290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84033054290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift */; }; 84033057290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84033056290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift */; }; @@ -2051,6 +2053,11 @@ 84DF21AD25363D28005454AE /* WalletAssetId+Chain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DF21AC25363D28005454AE /* WalletAssetId+Chain.swift */; }; 84DF21B12536DDC1005454AE /* TransferConfirmCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DF21B02536DDC1005454AE /* TransferConfirmCommand.swift */; }; 84DF21B525388B35005454AE /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DF21B425388B35005454AE /* Scheduler.swift */; }; + 84E0EE04292D336C008B2953 /* GovernanceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E0EE03292D336C008B2953 /* GovernanceType.swift */; }; + 84E0EE06292D3A58008B2953 /* AssetSelectionBaseProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E0EE05292D3A58008B2953 /* AssetSelectionBaseProtocols.swift */; }; + 84E0EE08292D3C2D008B2953 /* GovernanceAssetSelectionProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E0EE07292D3C2D008B2953 /* GovernanceAssetSelectionProtocols.swift */; }; + 84E0EE0A292D3CB4008B2953 /* GovernanceAssetSelectionWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E0EE09292D3CB4008B2953 /* GovernanceAssetSelectionWireframe.swift */; }; + 84E0EE0C292D402C008B2953 /* GovernanceAssetSelectionViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E0EE0B292D402C008B2953 /* GovernanceAssetSelectionViewFactory.swift */; }; 84E172CF28BE468D00DC85B6 /* MessageSheetPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E172CE28BE468D00DC85B6 /* MessageSheetPresentable.swift */; }; 84E172D128BF383B00DC85B6 /* Array+Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E172D028BF383B00DC85B6 /* Array+Dictionary.swift */; }; 84E1CCF5260DCB91001E81B5 /* SwitchAccount+WalletManagementWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1CCF4260DCB91001E81B5 /* SwitchAccount+WalletManagementWireframe.swift */; }; @@ -3342,6 +3349,8 @@ 8402CC9D275B946100E5BF30 /* DAppItemViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppItemViewCell.swift; sourceTree = ""; }; 840302DD292CE3EA0013F356 /* StorageEntryMetadata+TypeCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StorageEntryMetadata+TypeCheck.swift"; sourceTree = ""; }; 840302DF292CE4030013F356 /* CodingFactory+TypeCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CodingFactory+TypeCheck.swift"; sourceTree = ""; }; + 840302E3292CFCF90013F356 /* AssetSelectionBasePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetSelectionBasePresenter.swift; sourceTree = ""; }; + 840302E7292D00380013F356 /* GovernanceAssetSelectionPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceAssetSelectionPresenter.swift; sourceTree = ""; }; 84031C16263EC95C008FD9D4 /* SetPayeeCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetPayeeCall.swift; sourceTree = ""; }; 84033054290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsUnlocksViewModel.swift; sourceTree = ""; }; 84033056290FD8AB009C18E6 /* ReferendumsUnlocksTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsUnlocksTableViewCell.swift; sourceTree = ""; }; @@ -5056,6 +5065,11 @@ 84DF21AC25363D28005454AE /* WalletAssetId+Chain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WalletAssetId+Chain.swift"; sourceTree = ""; }; 84DF21B02536DDC1005454AE /* TransferConfirmCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferConfirmCommand.swift; sourceTree = ""; }; 84DF21B425388B35005454AE /* Scheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scheduler.swift; sourceTree = ""; }; + 84E0EE03292D336C008B2953 /* GovernanceType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceType.swift; sourceTree = ""; }; + 84E0EE05292D3A58008B2953 /* AssetSelectionBaseProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetSelectionBaseProtocols.swift; sourceTree = ""; }; + 84E0EE07292D3C2D008B2953 /* GovernanceAssetSelectionProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceAssetSelectionProtocols.swift; sourceTree = ""; }; + 84E0EE09292D3CB4008B2953 /* GovernanceAssetSelectionWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceAssetSelectionWireframe.swift; sourceTree = ""; }; + 84E0EE0B292D402C008B2953 /* GovernanceAssetSelectionViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceAssetSelectionViewFactory.swift; sourceTree = ""; }; 84E172CE28BE468D00DC85B6 /* MessageSheetPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSheetPresentable.swift; sourceTree = ""; }; 84E172D028BF383B00DC85B6 /* Array+Dictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Dictionary.swift"; sourceTree = ""; }; 84E1CCF4260DCB91001E81B5 /* SwitchAccount+WalletManagementWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwitchAccount+WalletManagementWireframe.swift"; sourceTree = ""; }; @@ -6853,6 +6867,17 @@ path = View; sourceTree = ""; }; + 840302E6292D00090013F356 /* GovernanceAssetSelection */ = { + isa = PBXGroup; + children = ( + 840302E7292D00380013F356 /* GovernanceAssetSelectionPresenter.swift */, + 84E0EE07292D3C2D008B2953 /* GovernanceAssetSelectionProtocols.swift */, + 84E0EE09292D3CB4008B2953 /* GovernanceAssetSelectionWireframe.swift */, + 84E0EE0B292D402C008B2953 /* GovernanceAssetSelectionViewFactory.swift */, + ); + path = GovernanceAssetSelection; + sourceTree = ""; + }; 8407715428CB7D22007DBD24 /* Base */ = { isa = PBXGroup; children = ( @@ -8951,6 +8976,7 @@ FD4B0C614F7A70D8FB51A1C3 /* GovernanceUnlockSetup */, ABAF6F503B172CEE34E19030 /* ReferendumFullDescription */, 77E4088EF503B8FD414F14EA /* GovernanceUnlockConfirm */, + 840302E6292D00090013F356 /* GovernanceAssetSelection */, ); path = Governance; sourceTree = ""; @@ -11803,6 +11829,7 @@ 845B07FC291634D4005785D3 /* DemocracyDecidingFunctionProtocol.swift */, 84C9CF3C291AF1B1002BF328 /* GovernanceOffchainApi.swift */, 849D321F291C26BA00D25839 /* GovernanceDAppList.swift */, + 84E0EE03292D336C008B2953 /* GovernanceType.swift */, ); path = Model; sourceTree = ""; @@ -12868,6 +12895,8 @@ 83AB0AD3A7CECD061611F60C /* AssetSelectionInteractor.swift */, 9622C6C3102EF12BEE78D63D /* AssetSelectionViewFactory.swift */, 840DC8412880AF440039A054 /* AssetSelectionViewController.swift */, + 840302E3292CFCF90013F356 /* AssetSelectionBasePresenter.swift */, + 84E0EE05292D3A58008B2953 /* AssetSelectionBaseProtocols.swift */, ); path = AssetSelection; sourceTree = ""; @@ -15551,6 +15580,7 @@ 8831F10028C65B95009F7682 /* AssetLock.swift in Sources */, 842B1806286506EE0014CC57 /* CrossChainTransferSetupProtocols.swift in Sources */, 84D1F2FB260F51770077DDFE /* SwitchAccount.swift in Sources */, + 84E0EE08292D3C2D008B2953 /* GovernanceAssetSelectionProtocols.swift in Sources */, 84466B3C28B7680300FA1E0D /* LedgerDiscoverInteractor.swift in Sources */, 843CE3AA27D22B5200436F4E /* UniquesDetailsInteractor.swift in Sources */, 8428765D24ADDE0200D91AD8 /* SettingsInteractor.swift in Sources */, @@ -16021,6 +16051,7 @@ 848FFE8325E686C200652AA5 /* StorageDecodingOperation.swift in Sources */, 8412219E28F0514400715C82 /* ReferendumsMetadataPreviewProviderSource.swift in Sources */, 8488ECDF258CE118004591CC /* PurchaseCompleted.swift in Sources */, + 840302E4292CFCF90013F356 /* AssetSelectionBasePresenter.swift in Sources */, 84AE7AA727D36E4D00495267 /* IconDetailsGenericView.swift in Sources */, 840BF22726C2C8A600E3A955 /* ChainSyncEvents.swift in Sources */, 843461E8290BF14400379936 /* ReferendumsSorting.swift in Sources */, @@ -16037,6 +16068,7 @@ 8425D0EC28FE9ACB003B782A /* Gov2ExtrinsicFactory.swift in Sources */, 84E1CCFA260DCBF9001E81B5 /* SwitchAccount+UsernameSetupWireframe.swift in Sources */, 8473F4BA282C012B007CC55A /* StakingRelaychainInteractor+InputProtocol.swift in Sources */, + 84E0EE0C292D402C008B2953 /* GovernanceAssetSelectionViewFactory.swift in Sources */, 848DAEFE282293DB00D56F55 /* ParachainStaking+Types.swift in Sources */, 8489A6E227FEFC730040C066 /* StakingRebondOption.swift in Sources */, 84CFF1E626526FBC00DB7CF7 /* StakingBondMoreInteractor.swift in Sources */, @@ -16088,6 +16120,7 @@ 84963D6E26F91826003FE8E4 /* RemoteSubscriptionRequests.swift in Sources */, 849DEC5925ED756F00C64C19 /* SubstrateCallFactory.swift in Sources */, 843612BD278FE54D00DC739E /* DAppOperationConfirmInteractor+Protocol.swift in Sources */, + 84E0EE0A292D3CB4008B2953 /* GovernanceAssetSelectionWireframe.swift in Sources */, 844DBC5E274D1B13009F8351 /* IconWithTitleSubtitleTableViewCell.swift in Sources */, 84DBEA42265E80DD00FDF73C /* LearnMoreViewModel.swift in Sources */, 888B853828ED966600AC9614 /* SkeletonableView.swift in Sources */, @@ -16362,6 +16395,7 @@ F40966C726B297D6008CD244 /* AnalyticsRewardsViewFactory.swift in Sources */, 846AF83E2525B85100868F37 /* WalletNetworkFacade.swift in Sources */, 84DD49F428EE91ED00B804F3 /* Gov2LocalMappingFactory.swift in Sources */, + 84E0EE04292D336C008B2953 /* GovernanceType.swift in Sources */, 8489EDBA264DB25500FF997E /* RecommendationsComposing.swift in Sources */, F41CEB88272FFCB700C06154 /* CrowdloanContributionViewModel.swift in Sources */, 8466781327EC5446007935D3 /* MultilineBalanceView.swift in Sources */, @@ -16468,6 +16502,7 @@ 842BDB25278C3ACB00AB4B5A /* DAppBrowserMetadataState.swift in Sources */, 64B508A1A3D820AA8DBCFAA3 /* AccountExportPasswordWireframe.swift in Sources */, F462B351260C7DBE0005AB01 /* StakingRewardHistoryTableCell.swift in Sources */, + 840302E8292D00380013F356 /* GovernanceAssetSelectionPresenter.swift in Sources */, AE89720825F12143008EC414 /* ValidatorInfoViewModel.swift in Sources */, 8499FE7327BE305100712589 /* JSONListConvertible.swift in Sources */, 845B821726EF7FED00D25C72 /* SelectedWalletSettings.swift in Sources */, @@ -16866,6 +16901,7 @@ 846A2606267C792000429A7F /* CrowdloanContributionResponse.swift in Sources */, 0C2AA829B5CB89B39E0FA95E /* CrowdloanContributionConfirmProtocols.swift in Sources */, 506F0D372BCC8302E513637C /* CrowdloanContributionConfirmWireframe.swift in Sources */, + 84E0EE06292D3A58008B2953 /* AssetSelectionBaseProtocols.swift in Sources */, D1C6EABB48DC3EE254E5A095 /* CrowdloanContributionConfirmPresenter.swift in Sources */, 843A2C7126A85B5B00266F53 /* GenericTitleValueView.swift in Sources */, 847F2D4F27AA695F00AFD476 /* AssetListGroupModel.swift in Sources */, diff --git a/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift index 5b9774d8d9..fb6337f676 100644 --- a/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift +++ b/novawallet/Common/DataProvider/GovMetadataLocalSubscriptionFactory.swift @@ -5,11 +5,11 @@ typealias ReferendumMetadataMapping = [ReferendumIdLocal: ReferendumMetadataLoca protocol GovMetadataLocalSubscriptionFactoryProtocol: AnyObject { func getMetadataProvider( - for chain: ChainModel + for option: GovernanceSelectedOption ) -> StreamableProvider? func getMetadataProvider( - for chain: ChainModel, + for option: GovernanceSelectedOption, referendumId: ReferendumIdLocal ) -> StreamableProvider? } @@ -44,14 +44,17 @@ final class GovMetadataLocalSubscriptionFactory { extension GovMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol { func getMetadataProvider( - for chain: ChainModel + for option: GovernanceSelectedOption ) -> StreamableProvider? { guard - let governanceApi = chain.externalApi?.governance, + case .governanceV1 = option.type, + let governanceApi = option.chain.externalApi?.governance, let apiType = GovernanceOffchainApi(rawValue: governanceApi.type) else { return nil } + let chain = option.chain + let chainId = chain.chainId let url = governanceApi.url @@ -103,16 +106,17 @@ extension GovMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFacto } func getMetadataProvider( - for chain: ChainModel, + for option: GovernanceSelectedOption, referendumId: ReferendumIdLocal ) -> StreamableProvider? { guard - let governanceApi = chain.externalApi?.governance, + case .governanceV1 = option.type, + let governanceApi = option.chain.externalApi?.governance, let apiType = GovernanceOffchainApi(rawValue: governanceApi.type) else { return nil } - let chainId = chain.chainId + let chainId = option.chain.chainId let url = governanceApi.url let identifier = "gov-metadata-details" + chainId + String(referendumId) diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift index 0207ba74d3..6d8958b3d0 100644 --- a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageHandler.swift @@ -4,12 +4,12 @@ import RobinHood protocol GovMetadataLocalStorageHandler: AnyObject { func handleGovernanceMetadataPreview( result: Result<[DataProviderChange], Error>, - chain: ChainModel + option: GovernanceSelectedOption ) func handleGovernanceMetadataDetails( result: Result, - chain: ChainModel, + option: GovernanceSelectedOption, referendumId: ReferendumIdLocal ) } @@ -17,12 +17,12 @@ protocol GovMetadataLocalStorageHandler: AnyObject { extension GovMetadataLocalStorageHandler { func handleGovernanceMetadataPreview( result _: Result<[DataProviderChange], Error>, - chain _: ChainModel + option _: GovernanceSelectedOption ) {} func handleGovernanceMetadataDetails( result _: Result, - chain _: ChainModel, + option _: GovernanceSelectedOption, referendumId _: ReferendumIdLocal ) {} } diff --git a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift index 318d6e1007..6e36cbe26c 100644 --- a/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/GovMetadataLocalStorageSubscriber.swift @@ -7,20 +7,20 @@ protocol GovMetadataLocalStorageSubscriber: AnyObject { var govMetadataLocalSubscriptionHandler: GovMetadataLocalStorageHandler { get } func subscribeGovernanceMetadata( - for chain: ChainModel + for option: GovernanceSelectedOption ) -> StreamableProvider? func subscribeGovernanceMetadata( - for chain: ChainModel, + for option: GovernanceSelectedOption, referendumId: ReferendumIdLocal ) -> StreamableProvider? } extension GovMetadataLocalStorageSubscriber { func subscribeGovernanceMetadata( - for chain: ChainModel + for option: GovernanceSelectedOption ) -> StreamableProvider? { - guard let provider = govMetadataLocalSubscriptionFactory.getMetadataProvider(for: chain) else { + guard let provider = govMetadataLocalSubscriptionFactory.getMetadataProvider(for: option) else { return nil } @@ -28,7 +28,7 @@ extension GovMetadataLocalStorageSubscriber { updateClosure = { [weak self] changes in self?.govMetadataLocalSubscriptionHandler.handleGovernanceMetadataPreview( result: .success(changes), - chain: chain + option: option ) return } @@ -36,7 +36,7 @@ extension GovMetadataLocalStorageSubscriber { let failureClosure: (Error) -> Void = { [weak self] error in self?.govMetadataLocalSubscriptionHandler.handleGovernanceMetadataPreview( result: .failure(error), - chain: chain + option: option ) return } @@ -60,12 +60,12 @@ extension GovMetadataLocalStorageSubscriber { } func subscribeGovernanceMetadata( - for chain: ChainModel, + for option: GovernanceSelectedOption, referendumId: ReferendumIdLocal ) -> StreamableProvider? { guard let provider = govMetadataLocalSubscriptionFactory.getMetadataProvider( - for: chain, + for: option, referendumId: referendumId ) else { return nil @@ -77,7 +77,7 @@ extension GovMetadataLocalStorageSubscriber { self?.govMetadataLocalSubscriptionHandler.handleGovernanceMetadataDetails( result: .success(item), - chain: chain, + option: option, referendumId: referendumId ) return @@ -86,7 +86,7 @@ extension GovMetadataLocalStorageSubscriber { let failureClosure: (Error) -> Void = { [weak self] error in self?.govMetadataLocalSubscriptionHandler.handleGovernanceMetadataDetails( result: .failure(error), - chain: chain, + option: option, referendumId: referendumId ) return diff --git a/novawallet/Common/Extension/SettingsExtension.swift b/novawallet/Common/Extension/SettingsExtension.swift index 95e44723fc..7c46fb768a 100644 --- a/novawallet/Common/Extension/SettingsExtension.swift +++ b/novawallet/Common/Extension/SettingsExtension.swift @@ -11,6 +11,7 @@ enum SettingsKey: String { case hidesZeroBalances case selectedCurrency case governanceChainId + case governanceType } extension SettingsManagerProtocol { @@ -56,6 +57,27 @@ extension SettingsManagerProtocol { } } + var governanceType: GovernanceType? { + get { + if let rawValue = string(for: SettingsKey.governanceType.rawValue) { + return GovernanceType(rawValue: rawValue) + } else { + return nil + } + } + + set { + if let existingValue = newValue { + set( + value: existingValue.rawValue, + for: SettingsKey.governanceType.rawValue + ) + } else { + removeValue(for: SettingsKey.governanceType.rawValue) + } + } + } + var stakingAsset: ChainAssetId? { get { value(of: ChainAssetId.self, for: SettingsKey.stakingAsset.rawValue) diff --git a/novawallet/Common/Storage/GovernanceChainSettings.swift b/novawallet/Common/Storage/GovernanceChainSettings.swift index 4afd53fff1..5137ae526a 100644 --- a/novawallet/Common/Storage/GovernanceChainSettings.swift +++ b/novawallet/Common/Storage/GovernanceChainSettings.swift @@ -2,7 +2,16 @@ import Foundation import SoraKeystore import RobinHood -final class GovernanceChainSettings: PersistentValueSettings { +struct GovernanceSelectedOption: Equatable { + let chain: ChainModel + let type: GovernanceType + + static func == (lhs: Self, rhs: Self) -> Bool { + lhs.chain.chainId == rhs.chain.chainId && lhs.type == rhs.type + } +} + +final class GovernanceChainSettings: PersistentValueSettings { let chainRegistry: ChainRegistryProtocol let settings: SettingsManagerProtocol @@ -14,8 +23,11 @@ final class GovernanceChainSettings: PersistentValueSettings { self.settings = settings } - override func performSetup(completionClosure: @escaping (Result) -> Void) { + override func performSetup( + completionClosure: @escaping (Result) -> Void + ) { let maybeChainId = settings.governanceChainId + let maybeGovernanceType = settings.governanceType var completed: Bool = false let mutex = NSLock() @@ -42,37 +54,69 @@ final class GovernanceChainSettings: PersistentValueSettings { completed = true - strongSelf.completeSetup(for: chains, currentChainId: maybeChainId, completionClosure: completionClosure) + strongSelf.completeSetup( + for: chains, + currentChainId: maybeChainId, + currentGovernanceType: maybeGovernanceType, + completionClosure: completionClosure + ) } } override func performSave( - value: ChainModel, - completionClosure: @escaping (Result + value: GovernanceSelectedOption, + completionClosure: @escaping (Result ) -> Void ) { - settings.governanceChainId = value.chainId + settings.governanceChainId = value.chain.chainId + settings.governanceType = value.type completionClosure(.success(value)) } private func completeSetup( for chains: [ChainModel], currentChainId: ChainModel.Id?, - completionClosure: @escaping (Result) -> Void + currentGovernanceType: GovernanceType?, + completionClosure: @escaping (Result) -> Void ) { - let selectedChain: ChainModel? - - if let chain = chains.first(where: { $0.chainId == currentChainId }) { - selectedChain = chain + let selectedOption: GovernanceSelectedOption? + + if + let chain = chains.first(where: { $0.chainId == currentChainId }), + chain.hasGovernance { + if + let currentGovernanceType = currentGovernanceType, + currentGovernanceType.compatible(with: chain) { + selectedOption = .init(chain: chain, type: currentGovernanceType) + } else { + selectedOption = createSelectedOption(for: chain) + } } else if let firstChain = chains.first(where: { $0.hasGovernance }) { - settings.governanceChainId = firstChain.chainId - selectedChain = firstChain + selectedOption = createSelectedOption(for: firstChain) } else { - selectedChain = nil + selectedOption = nil + } + + if let chainId = selectedOption?.chain.chainId, chainId != currentChainId { + settings.governanceChainId = chainId + } + + if let type = selectedOption?.type, type != currentGovernanceType { + settings.governanceType = type } chainRegistry.chainsUnsubscribe(self) - completionClosure(.success(selectedChain)) + completionClosure(.success(selectedOption)) + } + + private func createSelectedOption(for chain: ChainModel) -> GovernanceSelectedOption? { + if chain.hasGovernanceV2 { + return .init(chain: chain, type: .governanceV2) + } else if chain.hasGovernanceV1 { + return .init(chain: chain, type: .governanceV1) + } else { + return nil + } } } diff --git a/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift b/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift index c53453b6d5..e05cb099f1 100644 --- a/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift +++ b/novawallet/Common/ViewModel/ChainBalanceViewModelFactory.swift @@ -9,12 +9,11 @@ final class ChainBalanceViewModelFactory { } func createViewModel( - from chainAsset: ChainAsset, + from title: String, + chainAsset: ChainAsset, balanceInPlank: BigUInt?, locale: Locale ) -> ChainBalanceViewModel { - let name = chainAsset.chain.name - let displayInfo = chainAsset.assetDisplayInfo let tokenFormatter = formatterFactory.createTokenFormatter(for: displayInfo) @@ -25,9 +24,24 @@ final class ChainBalanceViewModelFactory { let decimalBalance = Decimal.fromSubstrateAmount(balanceInPlank, precision: displayInfo.assetPrecision) { let balanceString = tokenFormatter.value(for: locale).stringFromDecimal(decimalBalance) - return ChainBalanceViewModel(name: name, icon: icon, balance: balanceString) + return ChainBalanceViewModel(name: title, icon: icon, balance: balanceString) } else { - return ChainBalanceViewModel(name: name, icon: icon, balance: nil) + return ChainBalanceViewModel(name: title, icon: icon, balance: nil) } } + + func createViewModel( + from chainAsset: ChainAsset, + balanceInPlank: BigUInt?, + locale: Locale + ) -> ChainBalanceViewModel { + let name = chainAsset.chain.name + + return createViewModel( + from: name, + chainAsset: chainAsset, + balanceInPlank: balanceInPlank, + locale: locale + ) + } } diff --git a/novawallet/Modules/AssetSelection/AssetSelectionBasePresenter.swift b/novawallet/Modules/AssetSelection/AssetSelectionBasePresenter.swift new file mode 100644 index 0000000000..a8cf0c293f --- /dev/null +++ b/novawallet/Modules/AssetSelection/AssetSelectionBasePresenter.swift @@ -0,0 +1,187 @@ +import Foundation +import SoraFoundation +import BigInt + +class AssetSelectionBasePresenter { + weak var view: AssetSelectionViewProtocol? + let baseWireframe: AssetSelectionBaseWireframeProtocol + let interactor: AssetSelectionInteractorInputProtocol + + let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol + + private(set) var assets: [ChainAsset] = [] + + private var accountBalances: [ChainAssetId: Result] = [:] + private var assetPrices: [ChainAssetId: PriceData] = [:] + + private var viewModels: [SelectableIconDetailsListViewModel] = [] + + init( + interactor: AssetSelectionInteractorInputProtocol, + baseWireframe: AssetSelectionBaseWireframeProtocol, + assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.interactor = interactor + self.baseWireframe = baseWireframe + self.assetBalanceFormatterFactory = assetBalanceFormatterFactory + self.localizationManager = localizationManager + } + + private func extractAvailableBalanceInPlank(for chainAsset: ChainAsset) -> BigUInt? { + guard + let balanceResult = accountBalances[chainAsset.chainAssetId], + case let .success(balance) = balanceResult else { + return nil + } + + return balance ?? 0 + } + + private func extractFiatBalance(for chainAsset: ChainAsset) -> Decimal? { + guard + let balanceResult = accountBalances[chainAsset.chainAssetId], + case let .success(balance) = balanceResult, + let priceString = assetPrices[chainAsset.chainAssetId]?.price, + let price = Decimal(string: priceString), + let balanceDecimal = Decimal.fromSubstrateAmount( + balance ?? 0, + precision: chainAsset.assetDisplayInfo.assetPrecision + ) else { + return nil + } + + return balanceDecimal * price + } + + func extractFormattedBalance(for chainAsset: ChainAsset) -> String? { + let assetInfo = chainAsset.assetDisplayInfo + + let maybeBalance: Decimal? + + if let balanceInPlank = extractAvailableBalanceInPlank(for: chainAsset) { + maybeBalance = Decimal.fromSubstrateAmount( + balanceInPlank, + precision: assetInfo.assetPrecision + ) + } else { + maybeBalance = 0.0 + } + + guard let balance = maybeBalance else { + return nil + } + + let tokenFormatter = assetBalanceFormatterFactory.createTokenFormatter(for: assetInfo) + .value(for: selectedLocale) + + return tokenFormatter.stringFromDecimal(balance) + } + + private func updateSorting() { + assets.sort { chainAsset1, chainAsset2 in + let balance1 = extractAvailableBalanceInPlank(for: chainAsset1) ?? 0 + let balance2 = extractAvailableBalanceInPlank(for: chainAsset2) ?? 0 + + let assetValue1 = extractFiatBalance(for: chainAsset1) ?? 0 + let assetValue2 = extractFiatBalance(for: chainAsset2) ?? 0 + + let priorityAndTestnetResult = ChainModelCompator.priorityAndTestnetComparator( + chain1: chainAsset1.chain, + chain2: chainAsset2.chain + ) + + if priorityAndTestnetResult != .orderedSame { + return priorityAndTestnetResult == .orderedAscending + } else if assetValue1 > 0, assetValue2 > 0 { + return assetValue1 > assetValue2 + } else if assetValue1 > 0 { + return true + } else if assetValue2 > 0 { + return false + } else if balance1 > 0, balance2 > 0 { + return balance1 > balance2 + } else if balance1 > 0 { + return true + } else if balance2 > 0 { + return false + } else { + return chainAsset1.chain.name.lexicographicallyPrecedes(chainAsset2.chain.name) + } + } + } + + func updateViewModels(_ viewModels: [SelectableIconDetailsListViewModel]) { + self.viewModels = viewModels + } + + func updateView() { + fatalError("Child presenter must override this method") + } + + func handleAssetSelection(at _: Int) { + fatalError("Child presenter must override this method") + } +} + +extension AssetSelectionBasePresenter: AssetSelectionPresenterProtocol { + var numberOfItems: Int { + viewModels.count + } + + func item(at index: Int) -> SelectableViewModelProtocol { + viewModels[index] + } + + func selectItem(at index: Int) { + handleAssetSelection(at: index) + } + + func setup() { + interactor.setup() + } +} + +extension AssetSelectionBasePresenter: AssetSelectionInteractorOutputProtocol { + func didReceiveChainAssets(result: Result<[ChainAsset], Error>) { + switch result { + case let .success(chainAssets): + assets = chainAssets + + updateSorting() + updateView() + case let .failure(error): + _ = baseWireframe.present(error: error, from: view, locale: selectedLocale) + } + } + + func didReceiveBalance(results: [ChainAssetId: Result]) { + results.forEach { key, value in + accountBalances[key] = value + } + + updateSorting() + updateView() + } + + func didReceivePrices(result: Result<[ChainAssetId: PriceData], Error>?) { + switch result { + case let .success(prices): + assetPrices = prices + + updateSorting() + updateView() + case .failure, .none: + // ignore any price errors as it is needed only for sorting + break + } + } +} + +extension AssetSelectionBasePresenter: Localizable { + func applyLocalization() { + if let view = view, view.isSetup { + updateView() + } + } +} diff --git a/novawallet/Modules/AssetSelection/AssetSelectionBaseProtocols.swift b/novawallet/Modules/AssetSelection/AssetSelectionBaseProtocols.swift new file mode 100644 index 0000000000..bf8525d897 --- /dev/null +++ b/novawallet/Modules/AssetSelection/AssetSelectionBaseProtocols.swift @@ -0,0 +1,3 @@ +import Foundation + +protocol AssetSelectionBaseWireframeProtocol: AlertPresentable, ErrorPresentable {} diff --git a/novawallet/Modules/AssetSelection/AssetSelectionPresenter.swift b/novawallet/Modules/AssetSelection/AssetSelectionPresenter.swift index c56a21bb92..0d060ab4a8 100644 --- a/novawallet/Modules/AssetSelection/AssetSelectionPresenter.swift +++ b/novawallet/Modules/AssetSelection/AssetSelectionPresenter.swift @@ -2,20 +2,12 @@ import Foundation import SoraFoundation import BigInt -final class AssetSelectionPresenter { - weak var view: AssetSelectionViewProtocol? - let wireframe: AssetSelectionWireframeProtocol - let interactor: AssetSelectionInteractorInputProtocol - let selectedChainAssetId: ChainAssetId? - - let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol - - private var assets: [ChainAsset] = [] - - private var accountBalances: [ChainAssetId: Result] = [:] - private var assetPrices: [ChainAssetId: PriceData] = [:] +final class AssetSelectionPresenter: AssetSelectionBasePresenter { + var wireframe: AssetSelectionWireframeProtocol? { + baseWireframe as? AssetSelectionWireframeProtocol + } - private var viewModels: [SelectableIconDetailsListViewModel] = [] + let selectedChainAssetId: ChainAssetId? init( interactor: AssetSelectionInteractorInputProtocol, @@ -24,98 +16,18 @@ final class AssetSelectionPresenter { assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, localizationManager: LocalizationManagerProtocol ) { - self.interactor = interactor - self.wireframe = wireframe self.selectedChainAssetId = selectedChainAssetId - self.assetBalanceFormatterFactory = assetBalanceFormatterFactory - self.localizationManager = localizationManager - } - - private func extractAvailableBalanceInPlank(for chainAsset: ChainAsset) -> BigUInt? { - guard - let balanceResult = accountBalances[chainAsset.chainAssetId], - case let .success(balance) = balanceResult else { - return nil - } - - return balance ?? 0 - } - - private func extractFiatBalance(for chainAsset: ChainAsset) -> Decimal? { - guard - let balanceResult = accountBalances[chainAsset.chainAssetId], - case let .success(balance) = balanceResult, - let priceString = assetPrices[chainAsset.chainAssetId]?.price, - let price = Decimal(string: priceString), - let balanceDecimal = Decimal.fromSubstrateAmount( - balance ?? 0, - precision: chainAsset.assetDisplayInfo.assetPrecision - ) else { - return nil - } - - return balanceDecimal * price - } - - private func extractFormattedBalance(for chainAsset: ChainAsset) -> String? { - let assetInfo = chainAsset.assetDisplayInfo - - let maybeBalance: Decimal? - - if let balanceInPlank = extractAvailableBalanceInPlank(for: chainAsset) { - maybeBalance = Decimal.fromSubstrateAmount( - balanceInPlank, - precision: assetInfo.assetPrecision - ) - } else { - maybeBalance = 0.0 - } - - guard let balance = maybeBalance else { - return nil - } - - let tokenFormatter = assetBalanceFormatterFactory.createTokenFormatter(for: assetInfo) - .value(for: selectedLocale) - return tokenFormatter.stringFromDecimal(balance) + super.init( + interactor: interactor, + baseWireframe: wireframe, + assetBalanceFormatterFactory: assetBalanceFormatterFactory, + localizationManager: localizationManager + ) } - private func updateSorting() { - assets.sort { chainAsset1, chainAsset2 in - let balance1 = extractAvailableBalanceInPlank(for: chainAsset1) ?? 0 - let balance2 = extractAvailableBalanceInPlank(for: chainAsset2) ?? 0 - - let assetValue1 = extractFiatBalance(for: chainAsset1) ?? 0 - let assetValue2 = extractFiatBalance(for: chainAsset2) ?? 0 - - let priorityAndTestnetResult = ChainModelCompator.priorityAndTestnetComparator( - chain1: chainAsset1.chain, - chain2: chainAsset2.chain - ) - - if priorityAndTestnetResult != .orderedSame { - return priorityAndTestnetResult == .orderedAscending - } else if assetValue1 > 0, assetValue2 > 0 { - return assetValue1 > assetValue2 - } else if assetValue1 > 0 { - return true - } else if assetValue2 > 0 { - return false - } else if balance1 > 0, balance2 > 0 { - return balance1 > balance2 - } else if balance1 > 0 { - return true - } else if balance2 > 0 { - return false - } else { - return chainAsset1.chain.name.lexicographicallyPrecedes(chainAsset2.chain.name) - } - } - } - - private func updateView() { - viewModels = assets.compactMap { chainAsset in + override func updateView() { + let viewModels: [SelectableIconDetailsListViewModel] = assets.compactMap { chainAsset in let chain = chainAsset.chain let asset = chainAsset.asset @@ -133,72 +45,16 @@ final class AssetSelectionPresenter { ) } - view?.didReload() - } -} - -extension AssetSelectionPresenter: AssetSelectionPresenterProtocol { - var numberOfItems: Int { - viewModels.count - } + updateViewModels(viewModels) - func item(at index: Int) -> SelectableViewModelProtocol { - viewModels[index] + view?.didReload() } - func selectItem(at index: Int) { + override func handleAssetSelection(at index: Int) { guard let view = view else { return } - wireframe.complete(on: view, selecting: assets[index]) - } - - func setup() { - interactor.setup() - } -} - -extension AssetSelectionPresenter: AssetSelectionInteractorOutputProtocol { - func didReceiveChainAssets(result: Result<[ChainAsset], Error>) { - switch result { - case let .success(chainAssets): - assets = chainAssets - - updateSorting() - updateView() - case let .failure(error): - _ = wireframe.present(error: error, from: view, locale: selectedLocale) - } - } - - func didReceiveBalance(results: [ChainAssetId: Result]) { - results.forEach { key, value in - accountBalances[key] = value - } - - updateSorting() - updateView() - } - - func didReceivePrices(result: Result<[ChainAssetId: PriceData], Error>?) { - switch result { - case let .success(prices): - assetPrices = prices - - updateSorting() - updateView() - case .failure, .none: - // ignore any price errors as it is needed only for sorting - break - } - } -} - -extension AssetSelectionPresenter: Localizable { - func applyLocalization() { - if let view = view, view.isSetup { - updateView() - } + wireframe?.complete(on: view, selecting: assets[index]) } } diff --git a/novawallet/Modules/AssetSelection/AssetSelectionProtocols.swift b/novawallet/Modules/AssetSelection/AssetSelectionProtocols.swift index 4d5e00630a..d790d6a691 100644 --- a/novawallet/Modules/AssetSelection/AssetSelectionProtocols.swift +++ b/novawallet/Modules/AssetSelection/AssetSelectionProtocols.swift @@ -6,7 +6,7 @@ protocol AssetSelectionPresenterProtocol: SelectionListPresenterProtocol { func setup() } -protocol AssetSelectionWireframeProtocol: AlertPresentable, ErrorPresentable { +protocol AssetSelectionWireframeProtocol: AssetSelectionBaseWireframeProtocol { func complete(on view: AssetSelectionViewProtocol, selecting chainAsset: ChainAsset) } diff --git a/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionPresenter.swift new file mode 100644 index 0000000000..6043686aba --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionPresenter.swift @@ -0,0 +1,93 @@ +import Foundation +import SoraFoundation + +final class GovernanceAssetSelectionPresenter: AssetSelectionBasePresenter { + var wireframe: GovernanceAssetSelectionWireframeProtocol? { + baseWireframe as? GovernanceAssetSelectionWireframeProtocol + } + + struct Option { + let chainAsset: ChainAsset + let governanceType: GovernanceType + } + + private var availableOptions: [Option] = [] + + private var selectedGovernanceType: GovernanceType? + private var selectedChainId: ChainModel.Id? + + init( + interactor: AssetSelectionInteractorInputProtocol, + wireframe: GovernanceAssetSelectionWireframeProtocol, + selectedChainId: ChainModel.Id?, + selectedGovernanceType: GovernanceType?, + assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.selectedChainId = selectedChainId + self.selectedGovernanceType = selectedGovernanceType + + super.init( + interactor: interactor, + baseWireframe: wireframe, + assetBalanceFormatterFactory: assetBalanceFormatterFactory, + localizationManager: localizationManager + ) + } + + private func createViewModel( + for chainAsset: ChainAsset, + governanceType: GovernanceType + ) -> SelectableIconDetailsListViewModel { + let chain = chainAsset.chain + let asset = chainAsset.asset + + let icon = RemoteImageViewModel(url: asset.icon ?? chain.icon) + let title = governanceType.title(for: chain) + let isSelected = selectedChainId == chain.chainId && selectedGovernanceType == governanceType + let balance = extractFormattedBalance(for: chainAsset) ?? "" + + return SelectableIconDetailsListViewModel( + title: title, + subtitle: balance, + icon: icon, + isSelected: isSelected + ) + } + + override func updateView() { + // show gov2 options first + availableOptions = assets.reduce(into: [Option]()) { accum, chainAsset in + if chainAsset.chain.hasGovernanceV2 { + accum.append(.init(chainAsset: chainAsset, governanceType: .governanceV2)) + } + } + + availableOptions = assets.reduce(into: availableOptions) { accum, chainAsset in + if chainAsset.chain.hasGovernanceV1 { + accum.append(.init(chainAsset: chainAsset, governanceType: .governanceV1)) + } + } + + let viewModels = availableOptions.map { + createViewModel(for: $0.chainAsset, governanceType: $0.governanceType) + } + + updateViewModels(viewModels) + + view?.didReload() + } + + override func handleAssetSelection(at index: Int) { + guard let view = view else { + return + } + + let option = availableOptions[index] + + wireframe?.complete( + on: view, + option: .init(chain: option.chainAsset.chain, type: option.governanceType) + ) + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionProtocols.swift b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionProtocols.swift new file mode 100644 index 0000000000..e1da74fcaf --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionProtocols.swift @@ -0,0 +1,12 @@ +import Foundation + +protocol GovernanceAssetSelectionDelegate: AnyObject { + func governanceAssetSelection( + view: AssetSelectionViewProtocol, + didCompleteWith option: GovernanceSelectedOption + ) +} + +protocol GovernanceAssetSelectionWireframeProtocol: AssetSelectionBaseWireframeProtocol { + func complete(on view: AssetSelectionViewProtocol, option: GovernanceSelectedOption) +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionViewFactory.swift new file mode 100644 index 0000000000..2f08f7941b --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionViewFactory.swift @@ -0,0 +1,62 @@ +import Foundation +import RobinHood +import SoraFoundation + +final class GovernanceAssetSelectionViewFactory { + static func createView( + for delegate: GovernanceAssetSelectionDelegate, + chainId: ChainModel.Id?, + governanceType: GovernanceType? + ) -> AssetSelectionViewProtocol? { + guard let currencyManager = CurrencyManager.shared else { + return nil + } + + let repository = ChainRepositoryFactory().createRepository( + for: nil, + sortDescriptors: [NSSortDescriptor.chainsByAddressPrefix] + ) + + let interactor = AssetSelectionInteractor( + selectedMetaAccount: SelectedWalletSettings.shared.value, + balanceSlice: \.freeInPlank, + repository: AnyDataProviderRepository(repository), + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + assetFilter: { $0.chain.hasGovernance && $0.asset.isUtility }, + currencyManager: currencyManager, + operationQueue: OperationManagerFacade.sharedDefaultQueue + ) + + let wireframe = GovernanceAssetSelectionWireframe(delegate: delegate) + + let assetBalanceFormatterFactory = AssetBalanceFormatterFactory() + + let localizationManager = LocalizationManager.shared + + let presenter = GovernanceAssetSelectionPresenter( + interactor: interactor, + wireframe: wireframe, + selectedChainId: chainId, + selectedGovernanceType: governanceType, + assetBalanceFormatterFactory: assetBalanceFormatterFactory, + localizationManager: localizationManager + ) + + let title = LocalizableResource { locale in + R.string.localizable.commonSelectAsset(preferredLanguages: locale.rLanguages) + } + + let view = AssetSelectionViewController( + nibName: R.nib.selectionListViewController.name, + localizedTitle: title, + presenter: presenter, + localizationManager: localizationManager + ) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionWireframe.swift b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionWireframe.swift new file mode 100644 index 0000000000..677af2ac7a --- /dev/null +++ b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionWireframe.swift @@ -0,0 +1,17 @@ +import Foundation + +final class GovernanceAssetSelectionWireframe { + weak var delegate: GovernanceAssetSelectionDelegate? + + init(delegate: GovernanceAssetSelectionDelegate) { + self.delegate = delegate + } +} + +extension GovernanceAssetSelectionWireframe: GovernanceAssetSelectionWireframeProtocol { + func complete(on view: AssetSelectionViewProtocol, option: GovernanceSelectedOption) { + view.controller.dismiss(animated: true, completion: nil) + + delegate?.governanceAssetSelection(view: view, didCompleteWith: option) + } +} diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift index c533323986..a083d2ae5d 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockConfirm/GovernanceUnlockConfirmViewFactory.swift @@ -7,18 +7,28 @@ struct GovernanceUnlockConfirmViewFactory { for state: GovernanceSharedState, initData: GovernanceUnlockConfirmInitData ) -> GovernanceUnlockConfirmViewProtocol? { + guard let option = state.settings.value else { + return nil + } + + let chain = option.chain + guard let wallet = SelectedWalletSettings.shared.value, - let chain = state.settings.value, let selectedAccount = wallet.fetchMetaChainAccount(for: chain.accountRequest()), - let interactor = createInteractor(for: state, chain: chain, selectedAccount: selectedAccount), + let interactor = createInteractor( + for: state, + option: option, + selectedAccount: selectedAccount + ), let assetInfo = chain.utilityAssetDisplayInfo(), - let currencyManager = CurrencyManager.shared, - let votingLockId = state.governanceId(for: chain) + let currencyManager = CurrencyManager.shared else { return nil } + let votingLockId = state.governanceId(for: option) + let wireframe = GovernanceUnlockConfirmWireframe() let balanceViewModelFactory = BalanceViewModelFactory( @@ -66,21 +76,24 @@ struct GovernanceUnlockConfirmViewFactory { private static func createInteractor( for state: GovernanceSharedState, - chain: ChainModel, + option: GovernanceSelectedOption, selectedAccount: MetaChainAccountResponse ) -> GovernanceUnlockConfirmInteractor? { + let chain = option.chain + guard let connection = state.chainRegistry.getConnection(for: chain.chainId), let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId), let subscriptionFactory = state.subscriptionFactory, let lockStateFactory = state.locksOperationFactory, - let extrinsicFactory = state.createExtrinsicFactory(for: chain), let blockTimeService = state.blockTimeService, let blockTimeFactory = state.createBlockTimeOperationFactory(), let currencyManager = CurrencyManager.shared else { return nil } + let extrinsicFactory = state.createExtrinsicFactory(for: option) + let operationQueue = OperationManagerFacade.sharedDefaultQueue let extrinsicService = ExtrinsicServiceFactory( diff --git a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift index 3b94389e50..c9eb779c03 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceUnlockSetup/GovernanceUnlockSetupViewFactory.swift @@ -8,7 +8,7 @@ struct GovernanceUnlockSetupViewFactory { ) -> GovernanceUnlockSetupViewProtocol? { guard let interactor = createInteractor(for: state), - let assetInfo = state.settings.value?.utilityAssetDisplayInfo(), + let assetInfo = state.settings.value?.chain.utilityAssetDisplayInfo(), let currencyManager = CurrencyManager.shared else { return nil } @@ -43,7 +43,7 @@ struct GovernanceUnlockSetupViewFactory { private static func createInteractor(for state: GovernanceSharedState) -> GovernanceUnlockSetupInteractor? { guard let wallet = SelectedWalletSettings.shared.value, - let chain = state.settings.value, + let chain = state.settings.value?.chain, let selectedAccount = wallet.fetchMetaChainAccount(for: chain.accountRequest()), let currencyManager = CurrencyManager.shared else { return nil diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift index d99016d8e4..fb2d3dcd43 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceSharedState.swift @@ -59,18 +59,19 @@ final class GovernanceSharedState { blockTimeService = newService } - func replaceGovernanceFactory(for chain: ChainModel?) { + func replaceGovernanceFactory(for option: GovernanceSelectedOption?) { subscriptionFactory = nil referendumsOperationFactory = nil locksOperationFactory = nil - guard let chain = chain else { + guard let option = option else { return } - let chainId = chain.chainId + let chainId = option.chain.chainId - if chain.hasGovernanceV2 { + switch option.type { + case .governanceV2: let operationFactory = Gov2OperationFactory( requestFactory: requestFactory, operationQueue: operationQueue @@ -89,7 +90,7 @@ final class GovernanceSharedState { requestFactory: requestFactory, unlocksCalculator: GovUnlocksCalculator() ) - } else if chain.hasGovernanceV1 { + case .governanceV1: let operationFactory = Gov1OperationFactory( requestFactory: requestFactory, operationQueue: operationQueue @@ -111,23 +112,27 @@ final class GovernanceSharedState { } } - func createExtrinsicFactory(for chain: ChainModel) -> GovernanceExtrinsicFactoryProtocol? { - if chain.hasGovernanceV2 { + func createExtrinsicFactory( + for option: GovernanceSelectedOption + ) -> GovernanceExtrinsicFactoryProtocol { + switch option.type { + case .governanceV2: return Gov2ExtrinsicFactory() - } else if chain.hasGovernanceV1 { + case .governanceV1: return Gov1ExtrinsicFactory() - } else { - return nil } } - func createActionsDetailsFactory(for chain: ChainModel) -> ReferendumActionOperationFactoryProtocol? { - if chain.hasGovernanceV2 { + func createActionsDetailsFactory( + for option: GovernanceSelectedOption + ) -> ReferendumActionOperationFactoryProtocol { + switch option.type { + case .governanceV2: return Gov2ActionOperationFactory( requestFactory: requestFactory, operationQueue: operationQueue ) - } else if chain.hasGovernanceV1 { + case .governanceV1: let gov2ActionsFactory = Gov2ActionOperationFactory( requestFactory: requestFactory, operationQueue: operationQueue @@ -138,23 +143,20 @@ final class GovernanceSharedState { requestFactory: requestFactory, operationQueue: operationQueue ) - } else { - return nil } } - func governanceId(for chain: ChainModel) -> String? { - if chain.hasGovernanceV2 { + func governanceId(for option: GovernanceSelectedOption) -> String { + switch option.type { + case .governanceV2: return ConvictionVoting.lockId - } else if chain.hasGovernanceV1 { + case .governanceV1: return Democracy.lockId - } else { - return nil } } func createBlockTimeOperationFactory() -> BlockTimeOperationFactoryProtocol? { - guard let chain = settings.value else { + guard let chain = settings.value?.chain else { return nil } diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceType.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceType.swift new file mode 100644 index 0000000000..57cb73c479 --- /dev/null +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceType.swift @@ -0,0 +1,30 @@ +import Foundation + +enum GovernanceType: String, Equatable { + case governanceV1 = "governance-v1" + case governanceV2 = "governance" + + func title(for chain: ChainModel) -> String { + guard let asset = chain.utilityAsset() else { + return "" + } + + let assetTitle = asset.name ?? chain.name + + switch self { + case .governanceV1: + return assetTitle + " " + "Governance v1" + case .governanceV2: + return assetTitle + " " + "OpenGov" + } + } + + func compatible(with chain: ChainModel) -> Bool { + switch self { + case .governanceV1: + return chain.hasGovernanceV1 + case .governanceV2: + return chain.hasGovernanceV2 + } + } +} diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift index 0c502db406..5530fe18b2 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsInteractor.swift @@ -9,7 +9,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { private(set) var actionDetails: ReferendumActionLocal? let selectedAccount: ChainAccountResponse? - let chain: ChainModel + let option: GovernanceSelectedOption let actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol let connection: JSONRPCEngine let runtimeProvider: RuntimeProviderProtocol @@ -32,10 +32,14 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { private var blockTimeCancellable: CancellableCall? private var dAppsCancellable: CancellableCall? + var chain: ChainModel { + option.chain + } + init( referendum: ReferendumLocal, selectedAccount: ChainAccountResponse?, - chain: ChainModel, + option: GovernanceSelectedOption, actionDetailsOperationFactory: ReferendumActionOperationFactoryProtocol, connection: JSONRPCEngine, runtimeProvider: RuntimeProviderProtocol, @@ -52,7 +56,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { ) { self.referendum = referendum self.selectedAccount = selectedAccount - self.chain = chain + self.option = option self.actionDetailsOperationFactory = actionDetailsOperationFactory self.connection = connection self.runtimeProvider = runtimeProvider @@ -285,7 +289,7 @@ final class ReferendumDetailsInteractor: AnyCancellableCleaning { makeAccountBasedSubscriptions() - metadataProvider = subscribeGovernanceMetadata(for: chain, referendumId: referendum.index) + metadataProvider = subscribeGovernanceMetadata(for: option, referendumId: referendum.index) if metadataProvider == nil { presenter?.didReceiveMetadata(nil) @@ -359,7 +363,7 @@ extension ReferendumDetailsInteractor: PriceLocalSubscriptionHandler, PriceLocal extension ReferendumDetailsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataLocalStorageHandler { func handleGovernanceMetadataDetails( result: Result, - chain _: ChainModel, + option _: GovernanceSelectedOption, referendumId _: ReferendumIdLocal ) { switch result { diff --git a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift index 317f9c07fe..096dc8164e 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumDetails/ReferendumDetailsViewFactory.swift @@ -50,7 +50,7 @@ struct ReferendumDetailsViewFactory { initData: ReferendumDetailsInitData ) -> ReferendumDetailsPresenter? { guard - let chain = state.settings.value, + let chain = state.settings.value?.chain, let assetInfo = chain.utilityAssetDisplayInfo(), let wallet = SelectedWalletSettings.shared.value else { return nil @@ -106,10 +106,12 @@ struct ReferendumDetailsViewFactory { currencyManager: CurrencyManagerProtocol, state: GovernanceSharedState ) -> ReferendumDetailsInteractor? { - guard let chain = state.settings.value else { + guard let option = state.settings.value else { return nil } + let chain = option.chain + let selectedAccount = SelectedWalletSettings.shared.value?.fetch(for: chain.accountRequest()) let chainRegistry = state.chainRegistry @@ -119,11 +121,12 @@ struct ReferendumDetailsViewFactory { let runtimeProvider = chainRegistry.getRuntimeProvider(for: chain.chainId), let blockTimeService = state.blockTimeService, let blockTimeFactory = state.createBlockTimeOperationFactory(), - let subscriptionFactory = state.subscriptionFactory, - let actionDetailsFactory = state.createActionsDetailsFactory(for: chain) else { + let subscriptionFactory = state.subscriptionFactory else { return nil } + let actionDetailsFactory = state.createActionsDetailsFactory(for: option) + let operationQueue = OperationManagerFacade.sharedDefaultQueue let requestFactory = StorageRequestFactory( remoteFactory: StorageKeyFactory(), @@ -142,7 +145,7 @@ struct ReferendumDetailsViewFactory { return ReferendumDetailsInteractor( referendum: referendum, selectedAccount: selectedAccount, - chain: chain, + option: option, actionDetailsOperationFactory: actionDetailsFactory, connection: connection, runtimeProvider: runtimeProvider, diff --git a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift index b614b9d71a..5417df494d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumFullDetails/ReferendumFullDetailsViewFactory.swift @@ -11,7 +11,7 @@ struct ReferendumFullDetailsViewFactory { identities: [AccountAddress: AccountIdentity] ) -> ReferendumFullDetailsViewProtocol? { guard - let chain = state.settings.value, + let chain = state.settings.value?.chain, let currencyManager = CurrencyManager.shared, let assetInfo = chain.utilityAssetDisplayInfo() else { return nil diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift index 21b286d009..210d08db0d 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteConfirm/ReferendumVoteConfirmViewFactory.swift @@ -4,11 +4,18 @@ import SubstrateSdk import SoraFoundation struct ReferendumVoteConfirmViewFactory { + // swiftlint:disable:next function_body_length static func createView( for state: GovernanceSharedState, newVote: ReferendumNewVote, initData: ReferendumVotingInitData ) -> ReferendumVoteConfirmViewProtocol? { + guard let option = state.settings.value else { + return nil + } + + let chain = option.chain + guard let currencyManager = CurrencyManager.shared, let interactor = createInteractor( @@ -16,16 +23,16 @@ struct ReferendumVoteConfirmViewFactory { referendum: newVote.index, currencyManager: currencyManager ), - let chain = state.settings.value, let assetDisplayInfo = chain.utilityAsset()?.displayInfo(with: chain.icon), let selectedAccount = SelectedWalletSettings.shared.value?.fetchMetaChainAccount( for: chain.accountRequest() - ), - let votingLockId = state.governanceId(for: chain) + ) else { return nil } + let votingLockId = state.governanceId(for: option) + let wireframe = ReferendumVoteConfirmWireframe() let localizationManager = LocalizationManager.shared @@ -84,18 +91,24 @@ struct ReferendumVoteConfirmViewFactory { ) -> ReferendumVoteConfirmInteractor? { let wallet: MetaAccountModel? = SelectedWalletSettings.shared.value + guard let option = state.settings.value else { + return nil + } + + let chain = option.chain + guard - let chain = state.settings.value, let selectedAccount = wallet?.fetchMetaChainAccount(for: chain.accountRequest()), let subscriptionFactory = state.subscriptionFactory, let lockStateFactory = state.locksOperationFactory, - let extrinsicFactory = state.createExtrinsicFactory(for: chain), let blockTimeService = state.blockTimeService, let blockTimeFactory = state.createBlockTimeOperationFactory() else { return nil } + let extrinsicFactory = state.createExtrinsicFactory(for: option) + guard let connection = state.chainRegistry.getConnection(for: chain.chainId), let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId) else { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift index 3d449ef67e..a72be5de91 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoteSetup/ReferendumVoteSetupViewFactory.swift @@ -60,14 +60,17 @@ struct ReferendumVoteSetupViewFactory { state: GovernanceSharedState ) -> ReferendumVoteSetupPresenter? { guard - let chain = state.settings.value, - let assetDisplayInfo = chain.utilityAssetDisplayInfo(), - let currencyManager = CurrencyManager.shared, - let votingLockId = state.governanceId(for: chain) + let option = state.settings.value, + let assetDisplayInfo = option.chain.utilityAssetDisplayInfo(), + let currencyManager = CurrencyManager.shared else { return nil } + let chain = option.chain + + let votingLockId = state.governanceId(for: option) + let balanceViewModelFactory = BalanceViewModelFactory( targetAssetInfo: assetDisplayInfo, priceAssetInfoFactory: PriceAssetInfoFactory(currencyManager: currencyManager) @@ -107,18 +110,24 @@ struct ReferendumVoteSetupViewFactory { ) -> ReferendumVoteSetupInteractor? { let wallet: MetaAccountModel? = SelectedWalletSettings.shared.value + guard let option = state.settings.value else { + return nil + } + + let chain = option.chain + guard - let chain = state.settings.value, let selectedAccount = wallet?.fetchMetaChainAccount(for: chain.accountRequest()), let subscriptionFactory = state.subscriptionFactory, let lockStateFactory = state.locksOperationFactory, - let extrinsicFactory = state.createExtrinsicFactory(for: chain), let blockTimeService = state.blockTimeService, let blockTimeFactory = state.createBlockTimeOperationFactory() else { return nil } + let extrinsicFactory = state.createExtrinsicFactory(for: option) + guard let connection = state.chainRegistry.getConnection(for: chain.chainId), let runtimeProvider = state.chainRegistry.getRuntimeProvider(for: chain.chainId) else { diff --git a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift index 2195702a7c..ae30b4a8c7 100644 --- a/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift +++ b/novawallet/Modules/Vote/Governance/ReferendumVoters/ReferendumVotersViewFactory.swift @@ -11,7 +11,7 @@ struct ReferendumVotersViewFactory { ) -> ReferendumVotersViewProtocol? { guard let interactor = createInteractor(for: state, referendum: referendum), - let chain = state.settings.value + let chain = state.settings.value?.chain else { return nil } @@ -52,7 +52,7 @@ struct ReferendumVotersViewFactory { for state: GovernanceSharedState, referendum: ReferendumLocal ) -> ReferendumVotersInteractor? { - guard let chain = state.settings.value else { + guard let chain = state.settings.value?.chain else { return nil } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift index 73e5584168..02ae5a4f2c 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsInteractor.swift @@ -88,34 +88,34 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani private func continueSetup() { applicationHandler.delegate = self - guard let chain = governanceState.settings.value else { + guard let option = governanceState.settings.value else { presenter?.didReceiveError(.settingsLoadFailed) return } - let accountResponse = selectedMetaAccount.fetch(for: chain.accountRequest()) + let accountResponse = selectedMetaAccount.fetch(for: option.chain.accountRequest()) - setup(with: accountResponse?.accountId, chain: chain) + setup(with: accountResponse?.accountId, option: option) } - private func setup(with accountId: AccountId?, chain: ChainModel) { - presenter?.didReceiveSelectedChain(chain) + private func setup(with accountId: AccountId?, option: GovernanceSelectedOption) { + presenter?.didReceiveSelectedOption(option) if let accountId = accountId { - subscribeToAssetBalance(for: accountId, chain: chain) + subscribeToAssetBalance(for: accountId, chain: option.chain) } else { presenter?.didReceiveAssetBalance(nil) } - subscribeToAssetPrice(for: chain) + subscribeToAssetPrice(for: option.chain) - setupBlockTimeService(for: chain) + setupBlockTimeService(for: option.chain) provideBlockTime() - setupSubscriptionFactory(for: chain) + setupSubscriptionFactory(for: option) - subscribeToBlockNumber(for: chain) - subscribeToMetadata(for: chain) + subscribeToBlockNumber(for: option.chain) + subscribeToMetadata(for: option) if let accountId = accountId { subscribeAccountVotes(for: accountId) @@ -136,8 +136,8 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani } } - private func setupSubscriptionFactory(for chain: ChainModel) { - governanceState.replaceGovernanceFactory(for: chain) + private func setupSubscriptionFactory(for option: GovernanceSelectedOption) { + governanceState.replaceGovernanceFactory(for: option) } private func subscribeToBlockNumber(for chain: ChainModel) { @@ -168,20 +168,21 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) } - private func subscribeToMetadata(for chain: ChainModel) { - metadataProvider = subscribeGovernanceMetadata(for: chain) + private func subscribeToMetadata(for option: GovernanceSelectedOption) { + metadataProvider = subscribeGovernanceMetadata(for: option) if metadataProvider == nil { presenter?.didReceiveReferendumsMetadata([]) } } - private func handleChainChange(for newChain: ChainModel) { + private func handleOptionChange(for newOption: GovernanceSelectedOption) { clear() - let accountResponse = selectedMetaAccount.fetch(for: newChain.accountRequest()) + let chain = newOption.chain + let accountResponse = selectedMetaAccount.fetch(for: chain.accountRequest()) - setup(with: accountResponse?.accountId, chain: newChain) + setup(with: accountResponse?.accountId, option: newOption) } private func provideBlockTime() { @@ -189,7 +190,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani blockTimeCancellable == nil, let blockTimeService = governanceState.blockTimeService, let blockTimeFactory = governanceState.createBlockTimeOperationFactory(), - let chain = governanceState.settings.value else { + let chain = governanceState.settings.value?.chain else { return } @@ -231,7 +232,7 @@ final class ReferendumsInteractor: AnyProviderAutoCleaning, AnyCancellableCleani return } - guard let chain = governanceState.settings.value else { + guard let chain = governanceState.settings.value?.chain else { presenter?.didReceiveError(.referendumsFetchFailed(PersistentValueSettingsError.missingValue)) return } @@ -316,21 +317,22 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { blockNumberSubscription?.removeObserver(self) blockNumberSubscription = nil - if let chain = governanceState.settings.value { + if let option = governanceState.settings.value { + let chain = option.chain let accountResponse = selectedMetaAccount.fetch(for: chain.accountRequest()) - setup(with: accountResponse?.accountId, chain: chain) + setup(with: accountResponse?.accountId, option: option) } } - func saveSelected(chainModel: ChainModel) { - if chainModel.chainId != governanceState.settings.value?.chainId { + func saveSelected(option: GovernanceSelectedOption) { + if option != governanceState.settings.value { clear() - governanceState.settings.save(value: chainModel, runningCompletionIn: .main) { [weak self] result in + governanceState.settings.save(value: option, runningCompletionIn: .main) { [weak self] result in switch result { - case let .success(chain): - self?.handleChainChange(for: chain) + case let .success(option): + self?.handleOptionChange(for: option) case let .failure(error): self?.presenter?.didReceiveError(.chainSaveFailed(error)) } @@ -339,7 +341,7 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { } func becomeOnline() { - if let chain = governanceState.settings.value { + if let chain = governanceState.settings.value?.chain { subscribeToBlockNumber(for: chain) } } @@ -359,7 +361,7 @@ extension ReferendumsInteractor: ReferendumsInteractorInputProtocol { } func refreshUnlockSchedule(for tracksVoting: ReferendumTracksVotingDistribution, blockHash: Data?) { - if let chain = governanceState.settings.value { + if let chain = governanceState.settings.value?.chain { clear(cancellable: &unlockScheduleCancellable) guard let connection = chainRegistry.getConnection(for: chain.chainId) else { @@ -419,9 +421,9 @@ extension ReferendumsInteractor: GovMetadataLocalStorageSubscriber, GovMetadataL func handleGovernanceMetadataPreview( result: Result<[DataProviderChange], Error>, - chain: ChainModel + option: GovernanceSelectedOption ) { - guard let currentChain = governanceState.settings.value, currentChain.chainId == chain.chainId else { + guard let currentOption = governanceState.settings.value, currentOption == option else { return } @@ -463,7 +465,7 @@ extension ReferendumsInteractor: PriceLocalSubscriptionHandler, PriceLocalStorag extension ReferendumsInteractor: GeneralLocalStorageSubscriber, GeneralLocalStorageHandler { func handleBlockNumber(result: Result, chainId: ChainModel.Id) { - guard let chain = governanceState.settings.value, chain.chainId == chainId else { + guard let chain = governanceState.settings.value?.chain, chain.chainId == chainId else { return } @@ -480,7 +482,7 @@ extension ReferendumsInteractor: GeneralLocalStorageSubscriber, GeneralLocalStor extension ReferendumsInteractor: SelectedCurrencyDepending { func applyCurrency() { - if presenter != nil, let chain = governanceState.settings.value { + if presenter != nil, let chain = governanceState.settings.value?.chain { subscribeToAssetPrice(for: chain) } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift index b9f1a52aea..646b111193 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsPresenter.swift @@ -15,7 +15,7 @@ final class ReferendumsPresenter { let logger: LoggerProtocol private var freeBalance: BigUInt? - private var chain: ChainModel? + private var selectedOption: GovernanceSelectedOption? private var price: PriceData? private var referendums: [ReferendumLocal]? private var referendumsMetadata: ReferendumMetadataMapping? @@ -28,6 +28,14 @@ final class ReferendumsPresenter { private var countdownTimer: CountdownTimer? private var timeModels: [UInt: StatusTimeViewModel?]? + private var chain: ChainModel? { + selectedOption?.chain + } + + private var governanceType: GovernanceType? { + selectedOption?.type + } + private lazy var chainBalanceFactory = ChainBalanceViewModelFactory() deinit { @@ -73,12 +81,16 @@ final class ReferendumsPresenter { } private func provideChainBalance() { - guard let chain = chain, let asset = chain.utilityAsset() else { + guard + let chain = chain, + let governanceType = governanceType, + let asset = chain.utilityAsset() else { return } let viewModel = chainBalanceFactory.createViewModel( - from: ChainAsset(chain: chain, asset: asset), + from: governanceType.title(for: chain), + chainAsset: ChainAsset(chain: chain, asset: asset), balanceInPlank: freeBalance, locale: selectedLocale ) @@ -268,16 +280,11 @@ extension ReferendumsPresenter: VoteChildPresenterProtocol { } func selectChain() { - guard let chain = chain, let asset = chain.utilityAsset() else { - return - } - - let chainAssetId = ChainAsset(chain: chain, asset: asset).chainAssetId - wireframe.selectChain( from: view, delegate: self, - selectedChainAssetId: chainAssetId + chainId: chain?.chainId, + governanceType: governanceType ) } } @@ -328,8 +335,8 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { refreshUnlockSchedule() } - func didReceiveSelectedChain(_ chain: ChainModel) { - self.chain = chain + func didReceiveSelectedOption(_ option: GovernanceSelectedOption) { + selectedOption = option provideChainBalance() updateReferendumsView() @@ -360,8 +367,8 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { } case .chainSaveFailed: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in - if let chain = self?.chain { - self?.interactor.saveSelected(chainModel: chain) + if let option = self?.selectedOption { + self?.interactor.saveSelected(option: option) } } case .referendumsFetchFailed: @@ -385,18 +392,21 @@ extension ReferendumsPresenter: ReferendumsInteractorOutputProtocol { } } -extension ReferendumsPresenter: AssetSelectionDelegate { - func assetSelection(view _: AssetSelectionViewProtocol, didCompleteWith chainAsset: ChainAsset) { - if chain?.chainId == chainAsset.chain.chainId { +extension ReferendumsPresenter: GovernanceAssetSelectionDelegate { + func governanceAssetSelection( + view _: AssetSelectionViewProtocol, + didCompleteWith option: GovernanceSelectedOption + ) { + if selectedOption == option { return } - chain = chainAsset.chain + selectedOption = option clearOnAssetSwitch() provideChainBalance() - interactor.saveSelected(chainModel: chainAsset.chain) + interactor.saveSelected(option: option) } } diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift index b39459c80d..87dbc42d72 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsProtocols.swift @@ -17,7 +17,7 @@ protocol ReferendumsPresenterProtocol: AnyObject { protocol ReferendumsInteractorInputProtocol: AnyObject { func setup() - func saveSelected(chainModel: ChainModel) + func saveSelected(option: GovernanceSelectedOption) func becomeOnline() func putOffline() func refresh() @@ -30,7 +30,7 @@ protocol ReferendumsInteractorOutputProtocol: AnyObject { func didReceiveReferendums(_ referendums: [ReferendumLocal]) func didReceiveReferendumsMetadata(_ changes: [DataProviderChange]) func didReceiveVoting(_ voting: CallbackStorageSubscriptionResult) - func didReceiveSelectedChain(_ chain: ChainModel) + func didReceiveSelectedOption(_ option: GovernanceSelectedOption) func didReceiveAssetBalance(_ balance: AssetBalance?) func didReceivePrice(_ price: PriceData?) func didReceiveBlockNumber(_ blockNumber: BlockNumber) @@ -42,8 +42,9 @@ protocol ReferendumsInteractorOutputProtocol: AnyObject { protocol ReferendumsWireframeProtocol: AlertPresentable, ErrorPresentable, CommonRetryable { func selectChain( from view: ControllerBackedProtocol?, - delegate: AssetSelectionDelegate, - selectedChainAssetId: ChainAssetId? + delegate: GovernanceAssetSelectionDelegate, + chainId: ChainModel.Id?, + governanceType: GovernanceType? ) func showReferendumDetails(from view: ControllerBackedProtocol?, initData: ReferendumDetailsInitData) diff --git a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift index 811c680f14..b017678ffa 100644 --- a/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift +++ b/novawallet/Modules/Vote/Governance/Referendums/ReferendumsWireframe.swift @@ -9,18 +9,14 @@ final class ReferendumsWireframe: ReferendumsWireframeProtocol { func selectChain( from view: ControllerBackedProtocol?, - delegate: AssetSelectionDelegate, - selectedChainAssetId: ChainAssetId? + delegate: GovernanceAssetSelectionDelegate, + chainId: ChainModel.Id?, + governanceType: GovernanceType? ) { - let assetFilter: (ChainAsset) -> Bool = { chainAsset in - chainAsset.chain.hasGovernance && chainAsset.asset.isUtility - } - - guard let selectionView = AssetSelectionViewFactory.createView( - delegate: delegate, - selectedChainAssetId: selectedChainAssetId, - balanceSlice: \.freeInPlank, - assetFilter: assetFilter + guard let selectionView = GovernanceAssetSelectionViewFactory.createView( + for: delegate, + chainId: chainId, + governanceType: governanceType ) else { return } From 8bdeb22d150f9a920e8b00a333d34b51a809591e Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 23 Nov 2022 01:00:46 +0500 Subject: [PATCH 224/229] fix options order --- .../GovernanceAssetSelectionPresenter.swift | 21 +++++- novawalletTests/Mocks/ModuleMocks.swift | 64 ------------------- 2 files changed, 18 insertions(+), 67 deletions(-) diff --git a/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionPresenter.swift b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionPresenter.swift index 6043686aba..03bca00e1d 100644 --- a/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionPresenter.swift +++ b/novawallet/Modules/Vote/Governance/GovernanceAssetSelection/GovernanceAssetSelectionPresenter.swift @@ -56,15 +56,30 @@ final class GovernanceAssetSelectionPresenter: AssetSelectionBasePresenter { } override func updateView() { - // show gov2 options first + // show gov2 options first but not testnets availableOptions = assets.reduce(into: [Option]()) { accum, chainAsset in - if chainAsset.chain.hasGovernanceV2 { + if chainAsset.chain.hasGovernanceV2, !chainAsset.chain.isTestnet { accum.append(.init(chainAsset: chainAsset, governanceType: .governanceV2)) } } + // then show gov1 options availableOptions = assets.reduce(into: availableOptions) { accum, chainAsset in - if chainAsset.chain.hasGovernanceV1 { + if chainAsset.chain.hasGovernanceV1, !chainAsset.chain.isTestnet { + accum.append(.init(chainAsset: chainAsset, governanceType: .governanceV1)) + } + } + + // then show gov2 testnets + availableOptions = assets.reduce(into: availableOptions) { accum, chainAsset in + if chainAsset.chain.hasGovernanceV2, chainAsset.chain.isTestnet { + accum.append(.init(chainAsset: chainAsset, governanceType: .governanceV2)) + } + } + + // finally show gov1 testnets + availableOptions = assets.reduce(into: availableOptions) { accum, chainAsset in + if chainAsset.chain.hasGovernanceV1, chainAsset.chain.isTestnet { accum.append(.init(chainAsset: chainAsset, governanceType: .governanceV1)) } } diff --git a/novawalletTests/Mocks/ModuleMocks.swift b/novawalletTests/Mocks/ModuleMocks.swift index b6daac4dc4..e6743b6352 100644 --- a/novawalletTests/Mocks/ModuleMocks.swift +++ b/novawalletTests/Mocks/ModuleMocks.swift @@ -6792,36 +6792,6 @@ import BigInt } - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", - parameters: (message, title, closeAction, view), - escapingParameters: (message, title, closeAction, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.present(message: message, title: title, closeAction: closeAction, from: view)) - - } - - - - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - - return cuckoo_manager.call("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", - parameters: (viewModel, style, view), - escapingParameters: (viewModel, style, view), - superclassCall: - - Cuckoo.MockManager.crashOnProtocolSuperclassCall() - , - defaultCall: __defaultImplStub!.present(viewModel: viewModel, style: style, from: view)) - - } - struct __StubbingProxy_AssetSelectionWireframeProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager @@ -6836,16 +6806,6 @@ import BigInt return .init(stub: cuckoo_manager.createStub(for: MockAssetSelectionWireframeProtocol.self, method: "complete(on: AssetSelectionViewProtocol, selecting: ChainAsset)", parameterMatchers: matchers)) } - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockAssetSelectionWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.ProtocolStubNoReturnFunction<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockAssetSelectionWireframeProtocol.self, method: "present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) - } - } struct __VerificationProxy_AssetSelectionWireframeProtocol: Cuckoo.VerificationProxy { @@ -6868,18 +6828,6 @@ import BigInt return cuckoo_manager.verify("complete(on: AssetSelectionViewProtocol, selecting: ChainAsset)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } - @discardableResult - func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] - return cuckoo_manager.verify("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - - @discardableResult - func present(viewModel: M1, style: M2, from view: M3) -> Cuckoo.__DoNotUse<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?), Void> where M1.MatchedType == AlertPresentableViewModel, M2.MatchedType == UIAlertController.Style, M3.OptionalMatchedType == ControllerBackedProtocol { - let matchers: [Cuckoo.ParameterMatcher<(AlertPresentableViewModel, UIAlertController.Style, ControllerBackedProtocol?)>] = [wrap(matchable: viewModel) { $0.0 }, wrap(matchable: style) { $0.1 }, wrap(matchable: view) { $0.2 }] - return cuckoo_manager.verify("present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) - } - } } @@ -6895,18 +6843,6 @@ import BigInt return DefaultValueRegistry.defaultValue(for: (Void).self) } - - - func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - - - - func present(viewModel: AlertPresentableViewModel, style: UIAlertController.Style, from view: ControllerBackedProtocol?) { - return DefaultValueRegistry.defaultValue(for: (Void).self) - } - } From 3206a3099112a169cf592eead5951ce2b65eaa3c Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 23 Nov 2022 01:59:23 +0500 Subject: [PATCH 225/229] fix execute call --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../SubstrateSdk/CallMetadata+TypeCheck.swift | 12 +++++ .../CodingFactory+TypeCheck.swift | 4 ++ novawallet/Common/Model/BlockWeights.swift | 10 +++- .../Network/JSONRPC/RuntimeDispatchInfo.swift | 2 +- .../RuntimeCoderFactory.swift | 5 ++ .../ExtrinsicService/XcmTransferService.swift | 18 +++++-- .../Substrate/Calls/Xcm/XcmExecute.swift | 51 +++++++++++++++++-- 8 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 novawallet/Common/Extension/SubstrateSdk/CallMetadata+TypeCheck.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 82d6d3382f..1493c3e982 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -2058,6 +2058,7 @@ 84E0EE08292D3C2D008B2953 /* GovernanceAssetSelectionProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E0EE07292D3C2D008B2953 /* GovernanceAssetSelectionProtocols.swift */; }; 84E0EE0A292D3CB4008B2953 /* GovernanceAssetSelectionWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E0EE09292D3CB4008B2953 /* GovernanceAssetSelectionWireframe.swift */; }; 84E0EE0C292D402C008B2953 /* GovernanceAssetSelectionViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E0EE0B292D402C008B2953 /* GovernanceAssetSelectionViewFactory.swift */; }; + 84E0EE0E292D69A9008B2953 /* CallMetadata+TypeCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E0EE0D292D69A9008B2953 /* CallMetadata+TypeCheck.swift */; }; 84E172CF28BE468D00DC85B6 /* MessageSheetPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E172CE28BE468D00DC85B6 /* MessageSheetPresentable.swift */; }; 84E172D128BF383B00DC85B6 /* Array+Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E172D028BF383B00DC85B6 /* Array+Dictionary.swift */; }; 84E1CCF5260DCB91001E81B5 /* SwitchAccount+WalletManagementWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1CCF4260DCB91001E81B5 /* SwitchAccount+WalletManagementWireframe.swift */; }; @@ -5070,6 +5071,7 @@ 84E0EE07292D3C2D008B2953 /* GovernanceAssetSelectionProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceAssetSelectionProtocols.swift; sourceTree = ""; }; 84E0EE09292D3CB4008B2953 /* GovernanceAssetSelectionWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceAssetSelectionWireframe.swift; sourceTree = ""; }; 84E0EE0B292D402C008B2953 /* GovernanceAssetSelectionViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceAssetSelectionViewFactory.swift; sourceTree = ""; }; + 84E0EE0D292D69A9008B2953 /* CallMetadata+TypeCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CallMetadata+TypeCheck.swift"; sourceTree = ""; }; 84E172CE28BE468D00DC85B6 /* MessageSheetPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSheetPresentable.swift; sourceTree = ""; }; 84E172D028BF383B00DC85B6 /* Array+Dictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Dictionary.swift"; sourceTree = ""; }; 84E1CCF4260DCB91001E81B5 /* SwitchAccount+WalletManagementWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwitchAccount+WalletManagementWireframe.swift"; sourceTree = ""; }; @@ -7749,6 +7751,7 @@ 8499FEC727BF73F400712589 /* StorageKeyFactory+Size.swift */, 840302DD292CE3EA0013F356 /* StorageEntryMetadata+TypeCheck.swift */, 840302DF292CE4030013F356 /* CodingFactory+TypeCheck.swift */, + 84E0EE0D292D69A9008B2953 /* CallMetadata+TypeCheck.swift */, ); path = SubstrateSdk; sourceTree = ""; @@ -15781,6 +15784,7 @@ 84744953289268770042FD80 /* WalletSwitchViewModel.swift in Sources */, 84FACCD925F8C22A00F32ED4 /* BigInt+Hex.swift in Sources */, F409672626B29B04008CD244 /* UIScrollView+ScrollToPage.swift in Sources */, + 84E0EE0E292D69A9008B2953 /* CallMetadata+TypeCheck.swift in Sources */, 844384AE28538F4700611CE2 /* UniformCurveRewardEngine.swift in Sources */, 846A2C4525271F0100731018 /* DateFormatter.swift in Sources */, F4F65C3326D8B81A002EE838 /* FWChartViewProtocol.swift in Sources */, diff --git a/novawallet/Common/Extension/SubstrateSdk/CallMetadata+TypeCheck.swift b/novawallet/Common/Extension/SubstrateSdk/CallMetadata+TypeCheck.swift new file mode 100644 index 0000000000..4f83ab47d1 --- /dev/null +++ b/novawallet/Common/Extension/SubstrateSdk/CallMetadata+TypeCheck.swift @@ -0,0 +1,12 @@ +import Foundation +import SubstrateSdk + +extension CallMetadata { + func isArgumentTypeOf(_ name: String, closure: (String) -> Bool) -> Bool { + guard let argument = arguments.first(where: { $0.name == name }) else { + return false + } + + return closure(argument.type) + } +} diff --git a/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift b/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift index 7a743e700e..e58e634405 100644 --- a/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift +++ b/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift @@ -9,4 +9,8 @@ extension RuntimeCoderFactoryProtocol { return getTypeNode(for: vectorNode.underlying.typeName) is U8Node } + + func isUInt64Type(_ type: String) -> Bool { + getTypeNode(for: type) is U64Node + } } diff --git a/novawallet/Common/Model/BlockWeights.swift b/novawallet/Common/Model/BlockWeights.swift index 3670c6901a..7c45fc2a37 100644 --- a/novawallet/Common/Model/BlockWeights.swift +++ b/novawallet/Common/Model/BlockWeights.swift @@ -1,12 +1,18 @@ import Foundation import SubstrateSdk +import BigInt enum BlockchainWeight { typealias WeightV1 = StringScaleMapper - struct WeightV2: Decodable { + struct WeightV1P5: Decodable { @StringCodable var refTime: UInt64 } + + struct WeightV2: Codable { + @StringCodable var refTime: BigUInt + @StringCodable var proofSize: UInt64 + } } struct BlockWeights: Decodable { @@ -19,7 +25,7 @@ struct BlockWeights: Decodable { init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - if let weight = try? container.decode(BlockchainWeight.WeightV2.self, forKey: .maxBlock) { + if let weight = try? container.decode(BlockchainWeight.WeightV1P5.self, forKey: .maxBlock) { maxBlock = weight.refTime } else { maxBlock = try container.decode(BlockchainWeight.WeightV1.self, forKey: .maxBlock).value diff --git a/novawallet/Common/Network/JSONRPC/RuntimeDispatchInfo.swift b/novawallet/Common/Network/JSONRPC/RuntimeDispatchInfo.swift index 3e2e3324b1..2f039fa6f7 100644 --- a/novawallet/Common/Network/JSONRPC/RuntimeDispatchInfo.swift +++ b/novawallet/Common/Network/JSONRPC/RuntimeDispatchInfo.swift @@ -67,7 +67,7 @@ struct RemoteRuntimeDispatchInfo: Decodable { fee = try container.decode(StringScaleMapper.self, forKey: .fee).value - if let remoteWeight = try? container.decode(BlockchainWeight.WeightV2.self, forKey: .weight) { + if let remoteWeight = try? container.decode(BlockchainWeight.WeightV1P5.self, forKey: .weight) { weight = remoteWeight.refTime } else { weight = try container.decode(BlockchainWeight.WeightV1.self, forKey: .weight).value diff --git a/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift b/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift index c11d0566a2..a67e476e72 100644 --- a/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift +++ b/novawallet/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeCoderFactory.swift @@ -12,6 +12,7 @@ protocol RuntimeCoderFactoryProtocol { func hasType(for name: String) -> Bool func getTypeNode(for name: String) -> Node? + func getCall(for codingPath: CallCodingPath) -> CallMetadata? } final class RuntimeCoderFactory: RuntimeCoderFactoryProtocol { @@ -71,4 +72,8 @@ final class RuntimeCoderFactory: RuntimeCoderFactoryProtocol { return node } } + + func getCall(for codingPath: CallCodingPath) -> CallMetadata? { + metadata.getCall(from: codingPath.moduleName, with: codingPath.callName) + } } diff --git a/novawallet/Common/Services/ExtrinsicService/XcmTransferService.swift b/novawallet/Common/Services/ExtrinsicService/XcmTransferService.swift index 16ce95466c..c774a4a390 100644 --- a/novawallet/Common/Services/ExtrinsicService/XcmTransferService.swift +++ b/novawallet/Common/Services/ExtrinsicService/XcmTransferService.swift @@ -39,7 +39,7 @@ final class XcmTransferService { let moduleResolutionOperation = ClosureOperation { let metadata = try coderFactoryOperation.extractNoCancellableResultData().metadata - guard let moduleName = Xcm.ExecuteCall.possibleModuleNames.first( + guard let moduleName = Xcm.possibleModuleNames.first( where: { metadata.getModuleIndex($0) != nil } ) else { throw XcmTransferServiceError.noXcmPalletFound @@ -113,13 +113,22 @@ final class XcmTransferService { let optChainAccount = wallet.fetch(for: chain.accountRequest()) let operationFactory = try createOperationFactory(for: chain, chainAccount: optChainAccount) + let coderFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() + let wrapper = operationFactory.estimateFeeOperation { builder in let moduleName = try moduleWrapper.targetOperation.extractNoCancellableResultData() - let call = Xcm.ExecuteCall(message: message, maxWeight: maxWeight) - return try builder.adding(call: call.runtimeCall(for: moduleName)) + let codingFactory = try coderFactoryOperation.extractNoCancellableResultData() + return try Xcm.appendExecuteCall( + for: message, + maxWeight: maxWeight, + module: moduleName, + codingFactory: codingFactory, + builder: builder + ) } wrapper.addDependency(wrapper: moduleWrapper) + wrapper.addDependency(operations: [coderFactoryOperation]) let mapperOperation = ClosureOperation { let response = try wrapper.targetOperation.extractNoCancellableResultData() @@ -133,7 +142,8 @@ final class XcmTransferService { mapperOperation.addDependency(wrapper.targetOperation) - let dependencies = moduleWrapper.allOperations + wrapper.allOperations + let dependencies = [coderFactoryOperation] + moduleWrapper.allOperations + + wrapper.allOperations return CompoundOperationWrapper(targetOperation: mapperOperation, dependencies: dependencies) } catch { diff --git a/novawallet/Common/Substrate/Calls/Xcm/XcmExecute.swift b/novawallet/Common/Substrate/Calls/Xcm/XcmExecute.swift index dd883dade6..836c6e3317 100644 --- a/novawallet/Common/Substrate/Calls/Xcm/XcmExecute.swift +++ b/novawallet/Common/Substrate/Calls/Xcm/XcmExecute.swift @@ -3,7 +3,10 @@ import SubstrateSdk import BigInt extension Xcm { - struct ExecuteCall: Codable { + static var possibleModuleNames: [String] { ["XcmPallet", "PolkadotXcm"] } + static var executeCallName: String { "execute" } + + struct ExecuteCallV1: Codable { // swiftlint:disable:next nesting enum CodingKeys: String, CodingKey { case message @@ -13,10 +16,50 @@ extension Xcm { let message: Xcm.Message @StringCodable var maxWeight: BigUInt - func runtimeCall(for moduleName: String) -> RuntimeCall { - RuntimeCall(moduleName: moduleName, callName: "execute", args: self) + func runtimeCall(for moduleName: String) -> RuntimeCall { + RuntimeCall(moduleName: moduleName, callName: Xcm.executeCallName, args: self) + } + } + + struct ExecuteCallV2: Codable { + // swiftlint:disable:next nesting + enum CodingKeys: String, CodingKey { + case message + case maxWeight = "max_weight" + } + + let message: Xcm.Message + let maxWeight: BlockchainWeight.WeightV2 + + func runtimeCall(for moduleName: String) -> RuntimeCall { + RuntimeCall(moduleName: moduleName, callName: Xcm.executeCallName, args: self) } + } + + static func appendExecuteCall( + for message: Xcm.Message, + maxWeight: BigUInt, + module: String, + codingFactory: RuntimeCoderFactoryProtocol, + builder: ExtrinsicBuilderProtocol + ) throws -> ExtrinsicBuilderProtocol { + let path = CallCodingPath(moduleName: module, callName: Xcm.executeCallName) + let isV1 = codingFactory.getCall(for: path)?.isArgumentTypeOf( + ExecuteCallV1.CodingKeys.maxWeight.rawValue + ) { argumentType in + codingFactory.isUInt64Type(argumentType) + } ?? true - static var possibleModuleNames: [String] { ["XcmPallet", "PolkadotXcm"] } + if isV1 { + let call = ExecuteCallV1(message: message, maxWeight: maxWeight) + return try builder.adding(call: call.runtimeCall(for: module)) + } else { + let call = ExecuteCallV2( + message: message, + maxWeight: .init(refTime: maxWeight, proofSize: 0) + ) + + return try builder.adding(call: call.runtimeCall(for: module)) + } } } From 2be31a5cd5d7edfeb9cf33a65423bcc0f5dc69fd Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 23 Nov 2022 10:47:57 +0500 Subject: [PATCH 226/229] add support for weight v2 for ExecuteCall --- .../CodingFactory+TypeCheck.swift | 8 +++ novawallet/Common/Model/BlockWeights.swift | 2 +- .../Substrate/Calls/Xcm/XcmExecute.swift | 61 ++++++++++--------- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift b/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift index e58e634405..46ba7cde1d 100644 --- a/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift +++ b/novawallet/Common/Extension/SubstrateSdk/CodingFactory+TypeCheck.swift @@ -13,4 +13,12 @@ extension RuntimeCoderFactoryProtocol { func isUInt64Type(_ type: String) -> Bool { getTypeNode(for: type) is U64Node } + + func isStructHasFieldsCount(_ type: String, count: Int) -> Bool { + guard let structNode = getTypeNode(for: type) as? StructNode else { + return false + } + + return structNode.typeMapping.count == count + } } diff --git a/novawallet/Common/Model/BlockWeights.swift b/novawallet/Common/Model/BlockWeights.swift index 7c45fc2a37..8b1bd7a229 100644 --- a/novawallet/Common/Model/BlockWeights.swift +++ b/novawallet/Common/Model/BlockWeights.swift @@ -5,7 +5,7 @@ import BigInt enum BlockchainWeight { typealias WeightV1 = StringScaleMapper - struct WeightV1P5: Decodable { + struct WeightV1P5: Codable { @StringCodable var refTime: UInt64 } diff --git a/novawallet/Common/Substrate/Calls/Xcm/XcmExecute.swift b/novawallet/Common/Substrate/Calls/Xcm/XcmExecute.swift index 836c6e3317..6cb2fbcc50 100644 --- a/novawallet/Common/Substrate/Calls/Xcm/XcmExecute.swift +++ b/novawallet/Common/Substrate/Calls/Xcm/XcmExecute.swift @@ -6,7 +6,7 @@ extension Xcm { static var possibleModuleNames: [String] { ["XcmPallet", "PolkadotXcm"] } static var executeCallName: String { "execute" } - struct ExecuteCallV1: Codable { + struct ExecuteCall: Codable { // swiftlint:disable:next nesting enum CodingKeys: String, CodingKey { case message @@ -14,24 +14,9 @@ extension Xcm { } let message: Xcm.Message - @StringCodable var maxWeight: BigUInt + let maxWeight: M - func runtimeCall(for moduleName: String) -> RuntimeCall { - RuntimeCall(moduleName: moduleName, callName: Xcm.executeCallName, args: self) - } - } - - struct ExecuteCallV2: Codable { - // swiftlint:disable:next nesting - enum CodingKeys: String, CodingKey { - case message - case maxWeight = "max_weight" - } - - let message: Xcm.Message - let maxWeight: BlockchainWeight.WeightV2 - - func runtimeCall(for moduleName: String) -> RuntimeCall { + func runtimeCall(for moduleName: String) -> RuntimeCall { RuntimeCall(moduleName: moduleName, callName: Xcm.executeCallName, args: self) } } @@ -44,22 +29,42 @@ extension Xcm { builder: ExtrinsicBuilderProtocol ) throws -> ExtrinsicBuilderProtocol { let path = CallCodingPath(moduleName: module, callName: Xcm.executeCallName) - let isV1 = codingFactory.getCall(for: path)?.isArgumentTypeOf( - ExecuteCallV1.CodingKeys.maxWeight.rawValue - ) { argumentType in + + guard let callType = codingFactory.getCall(for: path) else { + return builder + } + + let paramName = ExecuteCall.CodingKeys.maxWeight.rawValue + + // v1 require only uint64 weight + let isV1 = callType.isArgumentTypeOf(paramName) { argumentType in codingFactory.isUInt64Type(argumentType) - } ?? true + } if isV1 { - let call = ExecuteCallV1(message: message, maxWeight: maxWeight) + let call = ExecuteCall(message: message, maxWeight: StringScaleMapper(value: maxWeight)) return try builder.adding(call: call.runtimeCall(for: module)) } else { - let call = ExecuteCallV2( - message: message, - maxWeight: .init(refTime: maxWeight, proofSize: 0) - ) + // verision 1.5 contains only 1 field and v2 contains 2 fields + let isV1P5 = callType.isArgumentTypeOf(paramName) { argumentType in + codingFactory.isStructHasFieldsCount(argumentType, count: 1) + } - return try builder.adding(call: call.runtimeCall(for: module)) + if isV1P5 { + let call = ExecuteCall( + message: message, + maxWeight: BlockchainWeight.WeightV1P5(refTime: UInt64(maxWeight)) + ) + + return try builder.adding(call: call.runtimeCall(for: module)) + } else { + let call = ExecuteCall( + message: message, + maxWeight: BlockchainWeight.WeightV2(refTime: maxWeight, proofSize: 0) + ) + + return try builder.adding(call: call.runtimeCall(for: module)) + } } } } From 672e6391874daf56fa90b6054be9e0ec6405acf0 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 23 Nov 2022 11:18:33 +0500 Subject: [PATCH 227/229] fix gov title when there is a single option --- novawallet/Modules/Vote/Governance/Model/GovernanceType.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/novawallet/Modules/Vote/Governance/Model/GovernanceType.swift b/novawallet/Modules/Vote/Governance/Model/GovernanceType.swift index 57cb73c479..dcaa79f0ba 100644 --- a/novawallet/Modules/Vote/Governance/Model/GovernanceType.swift +++ b/novawallet/Modules/Vote/Governance/Model/GovernanceType.swift @@ -11,6 +11,10 @@ enum GovernanceType: String, Equatable { let assetTitle = asset.name ?? chain.name + guard chain.hasGovernanceV1, chain.hasGovernanceV2 else { + return assetTitle + } + switch self { case .governanceV1: return assetTitle + " " + "Governance v1" From 0e32c133ac7bb1604c7a221cb454a679413a1eb1 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 23 Nov 2022 11:33:52 +0500 Subject: [PATCH 228/229] fix comments --- .../Substrate/Types/Democracy/DemocracyReferendum.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift index 5983ebf273..1a977342ba 100644 --- a/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift +++ b/novawallet/Common/Substrate/Types/Democracy/DemocracyReferendum.swift @@ -20,8 +20,10 @@ extension Democracy { @StringCodable var end: BlockNumber @StringCodable var delay: BlockNumber - // + /// legacy proposal hash for backward compatability let proposalHash: BytesCodable? + + /// actual proposal let proposal: Proposal? let threshold: Democracy.VoteThreshold From 022d2d576c29c911220dc41dba1da0fb2a818326 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 23 Nov 2022 12:20:53 +0500 Subject: [PATCH 229/229] add lock for connection pool syncing --- .../ConnectionPool/ConnectionPool.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/novawallet/Common/Services/ChainRegistry/ConnectionPool/ConnectionPool.swift b/novawallet/Common/Services/ChainRegistry/ConnectionPool/ConnectionPool.swift index 25b43549ec..772f66b7d4 100644 --- a/novawallet/Common/Services/ChainRegistry/ConnectionPool/ConnectionPool.swift +++ b/novawallet/Common/Services/ChainRegistry/ConnectionPool/ConnectionPool.swift @@ -135,6 +135,12 @@ extension ConnectionPool: WebSocketEngineDelegate { extension ConnectionPool: ApplicationHandlerDelegate { func didReceiveDidBecomeActive(notification _: Notification) { + mutex.lock() + + defer { + mutex.unlock() + } + connections.values.forEach { wrapper in guard let connection = wrapper.target as? ChainConnection else { return @@ -145,6 +151,12 @@ extension ConnectionPool: ApplicationHandlerDelegate { } func didReceiveDidEnterBackground(notification _: Notification) { + mutex.lock() + + defer { + mutex.unlock() + } + connections.values.forEach { wrapper in guard let connection = wrapper.target as? ChainConnection else { return