Skip to content

Commit

Permalink
MOB-2194 - Request MPC recovery kit (#680)
Browse files Browse the repository at this point in the history
* Fixed preview target

* Updated recovery view subtitle

* Updated recovery illustration

* Added forgot password button if failed during activation

* Implemented MPCRequestRecoveryView UI

* Implemented MPCRecoveryRequestedView UI

* Implemented API call to request recovery

* Display request recovery flow

* Updated copies

* Handle email truncation
  • Loading branch information
Oleg-Pecheneg authored Oct 8, 2024
1 parent ee892ed commit 05674f0
Show file tree
Hide file tree
Showing 35 changed files with 640 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import Foundation
import Combine

final class CoinRecordsService: CoinRecordsServiceProtocol {
func refreshCurrencies() {

}

private(set) var eventsPublisher = PassthroughSubject<CoinRecordsEvent, Never>()

func getCurrencies() async -> [CoinRecord] {
Expand All @@ -25,8 +29,4 @@ final class CoinRecordsService: CoinRecordsServiceProtocol {
expandedTicker: "crypto.BTC.address",
regexPattern: BlockchainType.Bitcoin.regexPattern)]
}

func refreshCurrencies(version: String) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,13 @@ extension FB_UD_MPC {

func submitBootstrapCode(_ code: String) async throws -> BootstrapCodeSubmitResponse {
await Task.sleep(seconds: 0.5)
// throw MPCWalletError.incorrectCode
return .init(accessToken: "sd", deviceId: "1")
}

func authNewDeviceWith(requestId: String, recoveryPhrase: String, accessToken: String) async throws {
await Task.sleep(seconds: 0.5)
// throw MPCWalletError.incorrectPassword
}

func initTransactionWithNewKeyMaterials(accessToken: String) async throws -> SetupTokenResponse {
Expand Down Expand Up @@ -136,6 +138,10 @@ extension FB_UD_MPC {
await Task.sleep(seconds: 0.5)
return .init(items: [])
}

func requestRecovery(_ accessToken: String, password: String) async throws {
await Task.sleep(seconds: 0.5)
}
}

struct MPCWalletsDefaultDataStorage: MPCWalletsDataStorage {
Expand Down
26 changes: 26 additions & 0 deletions unstoppable-ios-app/domains-manager-ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,8 @@
C68F157A2BD76A550049BFA2 /* MPCWalletActivationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C68F15782BD76A550049BFA2 /* MPCWalletActivationState.swift */; };
C68F157C2BD76A650049BFA2 /* MPCWalletActivationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C68F157B2BD76A650049BFA2 /* MPCWalletActivationError.swift */; };
C68F157D2BD76A650049BFA2 /* MPCWalletActivationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C68F157B2BD76A650049BFA2 /* MPCWalletActivationError.swift */; };
C6918C692CB54EFD00036C63 /* MPCWalletMetadataDisplayInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6918C682CB54EFD00036C63 /* MPCWalletMetadataDisplayInfo.swift */; };
C6918C6A2CB54EFD00036C63 /* MPCWalletMetadataDisplayInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6918C682CB54EFD00036C63 /* MPCWalletMetadataDisplayInfo.swift */; };
C691CF6C28BE4DA80077C59F /* HelveticaNeue-Custom.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C691CF6B28BE4DA80077C59F /* HelveticaNeue-Custom.ttf */; };
C692C304282E012900C31393 /* WalletDataValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C692C303282E012900C31393 /* WalletDataValidator.swift */; };
C692C309282E0BC300C31393 /* EnterBackupToBackupWalletPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C692C308282E0BC300C31393 /* EnterBackupToBackupWalletPresenter.swift */; };
Expand Down Expand Up @@ -1477,6 +1479,10 @@
C69698982ACBCDDB0000738C /* PushWebSocketsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69698972ACBCDDB0000738C /* PushWebSocketsService.swift */; };
C696989A2ACBCE640000738C /* PushMessagingWebSocketsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69698992ACBCE640000738C /* PushMessagingWebSocketsService.swift */; };
C696989C2ACC043A0000738C /* MessagingCommunitiesChatDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = C696989B2ACC043A0000738C /* MessagingCommunitiesChatDetails.swift */; };
C69CA5D02CB5210D00C30DF7 /* MPCRequestRecoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69CA5CF2CB5210D00C30DF7 /* MPCRequestRecoveryView.swift */; };
C69CA5D12CB5210D00C30DF7 /* MPCRequestRecoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69CA5CF2CB5210D00C30DF7 /* MPCRequestRecoveryView.swift */; };
C69CA5D32CB5211C00C30DF7 /* MPCRecoveryRequestedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69CA5D22CB5211C00C30DF7 /* MPCRecoveryRequestedView.swift */; };
C69CA5D42CB5211C00C30DF7 /* MPCRecoveryRequestedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69CA5D22CB5211C00C30DF7 /* MPCRecoveryRequestedView.swift */; };
C69F99202A9F1264004B1958 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69F99102A9F1264004B1958 /* Line.swift */; };
C69F99212A9F1264004B1958 /* HexagonShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69F99112A9F1264004B1958 /* HexagonShape.swift */; };
C69F99232A9F1264004B1958 /* AttributedText.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69F99142A9F1264004B1958 /* AttributedText.swift */; };
Expand Down Expand Up @@ -3680,6 +3686,7 @@
C68F15752BD769830049BFA2 /* MPCWalletStateCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPCWalletStateCardView.swift; sourceTree = "<group>"; };
C68F15782BD76A550049BFA2 /* MPCWalletActivationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPCWalletActivationState.swift; sourceTree = "<group>"; };
C68F157B2BD76A650049BFA2 /* MPCWalletActivationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPCWalletActivationError.swift; sourceTree = "<group>"; };
C6918C682CB54EFD00036C63 /* MPCWalletMetadataDisplayInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPCWalletMetadataDisplayInfo.swift; sourceTree = "<group>"; };
C691CF6B28BE4DA80077C59F /* HelveticaNeue-Custom.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "HelveticaNeue-Custom.ttf"; sourceTree = "<group>"; };
C692C303282E012900C31393 /* WalletDataValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletDataValidator.swift; sourceTree = "<group>"; };
C692C308282E0BC300C31393 /* EnterBackupToBackupWalletPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterBackupToBackupWalletPresenter.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3733,6 +3740,8 @@
C69698972ACBCDDB0000738C /* PushWebSocketsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushWebSocketsService.swift; sourceTree = "<group>"; };
C69698992ACBCE640000738C /* PushMessagingWebSocketsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushMessagingWebSocketsService.swift; sourceTree = "<group>"; };
C696989B2ACC043A0000738C /* MessagingCommunitiesChatDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagingCommunitiesChatDetails.swift; sourceTree = "<group>"; };
C69CA5CF2CB5210D00C30DF7 /* MPCRequestRecoveryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPCRequestRecoveryView.swift; sourceTree = "<group>"; };
C69CA5D22CB5211C00C30DF7 /* MPCRecoveryRequestedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPCRecoveryRequestedView.swift; sourceTree = "<group>"; };
C69F99102A9F1264004B1958 /* Line.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
C69F99112A9F1264004B1958 /* HexagonShape.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HexagonShape.swift; sourceTree = "<group>"; };
C69F99142A9F1264004B1958 /* AttributedText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributedText.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4668,6 +4677,7 @@
C6A231FB2BEB494D0037E093 /* WalletDetailsDomainItemView.swift */,
C6A231FE2BEB52CB0037E093 /* WalletSourceImageView.swift */,
C6A232012BEB53310037E093 /* RenameWalletView.swift */,
C6918C682CB54EFD00036C63 /* MPCWalletMetadataDisplayInfo.swift */,
);
path = WalletDetails;
sourceTree = "<group>";
Expand Down Expand Up @@ -7190,6 +7200,15 @@
path = "domains-manager-ios-preview";
sourceTree = "<group>";
};
C69CA5CB2CB5140200C30DF7 /* Recovery */ = {
isa = PBXGroup;
children = (
C69CA5CF2CB5210D00C30DF7 /* MPCRequestRecoveryView.swift */,
C69CA5D22CB5211C00C30DF7 /* MPCRecoveryRequestedView.swift */,
);
path = Recovery;
sourceTree = "<group>";
};
C69F990E2A9F1264004B1958 /* CommonViews */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -7795,6 +7814,7 @@
C6BF801B2BA2B53F00CC4CB3 /* MPC */ = {
isa = PBXGroup;
children = (
C69CA5CB2CB5140200C30DF7 /* Recovery */,
C640F3712C082C2E009EB0F9 /* Activate */,
C6952A5B2BC6648900F4B475 /* PurchaseMPCFlow */,
C6952A322BC4EE2D00F4B475 /* MPCWalletsService */,
Expand Down Expand Up @@ -9060,6 +9080,7 @@
C6526DD929D2DF6E00D6F2EB /* LoginWithEmailInAppViewPresenter.swift in Sources */,
C63095D62B0DA61600205054 /* PublishingAppStorage.swift in Sources */,
C6B65F9E2B57876F006D1812 /* HomeWalletNFTCellView.swift in Sources */,
C6918C692CB54EFD00036C63 /* MPCWalletMetadataDisplayInfo.swift in Sources */,
29BECD182979BE4000662FC1 /* Date.swift in Sources */,
C61308922A7A22AD00E7CE21 /* SwiftUIZoomableContainer.swift in Sources */,
C679B605291A579500F543A7 /* DomainProfileUpdatingRecordsSection.swift in Sources */,
Expand Down Expand Up @@ -9286,6 +9307,7 @@
C6F3FD632AAA11E700208679 /* PullUpNamespace.swift in Sources */,
C6C99582289D313D00367362 /* CNavigationBarContentView.swift in Sources */,
C6D5DAE928374C7300379C38 /* WalletAddressFieldCollectionCell.swift in Sources */,
C69CA5D42CB5211C00C30DF7 /* MPCRecoveryRequestedView.swift in Sources */,
C6B65F942B5665F0006D1812 /* HomeTabView.swift in Sources */,
C6BF80352BA2ED7100CC4CB3 /* FireblockJoinWalletHandlerImplementation.swift in Sources */,
C628E37227FDE1D60044E408 /* UDSubtitleLabel.swift in Sources */,
Expand Down Expand Up @@ -9519,6 +9541,7 @@
C6B65F7E2B55153E006D1812 /* HomeWalletView+Entities.swift in Sources */,
C6D5DAD428374B4600379C38 /* ManageMultiChainDomainAddressesViewController.swift in Sources */,
29BECD22297ABF3C00662FC1 /* UDWalletWithPrivateSeed.swift in Sources */,
C69CA5D02CB5210D00C30DF7 /* MPCRequestRecoveryView.swift in Sources */,
C60C298C2834E30000626851 /* GroupedCoinRecord.swift in Sources */,
C66430FD28D8B85800A9C734 /* ConnectExternalWalletViewPresenter.swift in Sources */,
C6D868192BF3218100EEBCFC /* EnterDomainEmailView.swift in Sources */,
Expand Down Expand Up @@ -10380,6 +10403,7 @@
C61808302B19AD9D0032E543 /* PreviewStripeService.swift in Sources */,
C6C837A22B5FF307000A6AF5 /* TabBarVisibleModifier.swift in Sources */,
C6D645BC2B1DBCE400D724AC /* ScrollViewOffsetListener.swift in Sources */,
C6918C6A2CB54EFD00036C63 /* MPCWalletMetadataDisplayInfo.swift in Sources */,
C621A43D2BB10D2900CB5CB9 /* SendCryptoQRWalletAddressScannerView.swift in Sources */,
C6C8F8352B217E9600A9834D /* CreateLocalWalletRecoveryWordsPresenter.swift in Sources */,
C632BE4B2BA5984100C95B2D /* PreviewMPCConnector.swift in Sources */,
Expand Down Expand Up @@ -11103,6 +11127,7 @@
C68F15742BD69FC50049BFA2 /* MPCActivateWalletEnterDataType.swift in Sources */,
C6D645AC2B1DBB5700D724AC /* CollectionReusableRoundedBackground.swift in Sources */,
C6952A3B2BC5053800F4B475 /* FB_UD_MPCBlockchain.swift in Sources */,
C69CA5D32CB5211C00C30DF7 /* MPCRecoveryRequestedView.swift in Sources */,
C67213E32BAA967C0075B9C7 /* SendCryptoAssetRootView.swift in Sources */,
C6C8F8E52B21836400A9834D /* ParkedDomainsFoundViewPresenter.swift in Sources */,
C6C8F8662B21811000A9834D /* UDWalletBackUpError.swift in Sources */,
Expand Down Expand Up @@ -11309,6 +11334,7 @@
C6D646462B1E084F00D724AC /* ViewPullUp.swift in Sources */,
C67B1DE02BFEF7BA00C2A4DA /* ReconnectMPCWalletPromptView.swift in Sources */,
C671CD1B2BC6809D005DA2FB /* DomainToPurchaseSuggestion.swift in Sources */,
C69CA5D12CB5210D00C30DF7 /* MPCRequestRecoveryView.swift in Sources */,
C6C8F8E22B21836400A9834D /* ParkedDomainsFoundViewController.swift in Sources */,
C6D647022B1ED7C300D724AC /* MessagingChatConversationState.swift in Sources */,
C6D647542B1EDBAE00D724AC /* WalletInfoBadgeView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ extension MockEntitiesFabric {
type: .generatedLocally),
.init(aliasName: "UD",
address: "0xCeBF5440FE9C85e037A80fFB4dF0F6a9BAcb3d01",
type: .generatedLocally)]
type: .generatedLocally),
.init(aliasName: "MPC",
address: "0xCeBF5440FE9C85e037A80fFB4dF0F6a9BAcb3d02",
type: .mpc)]

static func mockExternalWallet(hasRRDomain: Bool = true) -> WalletEntity {
let address = "0x84585360d34f6c72BE438fdde7147D27d2A85f9f"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1312,6 +1312,15 @@ extension String {
static let sendCrypto = "SEND_CRYPTO"
static let mpcForgotPasswordTitle = "MPC_FORGOT_PASSWORD_TITLE"
static let mpcForgotPasswordSubtitle = "MPC_FORGOT_PASSWORD_SUBTITLE"
static let mpcForgotPasswordSubtitleHighlights = "MPC_FORGOT_PASSWORD_SUBTITLE_HIGHLIGHTS"
static let forgotPasswordTitle = "FORGOT_PASSWORD_TITLE"
static let mpcRequestRecoveryTitle = "MPC_REQUEST_RECOVERY_TITLE"
static let mpcRequestRecoverySubtitle = "MPC_REQUEST_RECOVERY_SUBTITLE"
static let mpcRecoveryRequestedTitle = "MPC_RECOVERY_REQUESTED_TITLE"
static let mpcRecoveryRequestedSubtitle = "MPC_RECOVERY_REQUESTED_SUBTITLE"
static let mpcRecoveryRequestedSubtitleHighlights = "MPC_RECOVERY_REQUESTED_SUBTITLE_HIGHLIGHTS"
static let mpcRecoveryRequestedHintNotShare = "MPC_RECOVERY_REQUESTED_HINT_NOT_SHARE"
static let mpcRecoveryRequestedHintPreviousInactive = "MPC_RECOVERY_REQUESTED_HINT_PREVIOUS_INACTIVE"

// Send crypto first time
static let sendCryptoFirstTimePullUpTitle = "SEND_CRYPTO_FIRST_TIME_PULL_UP_TITLE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ final class HomeTabRouter: ObservableObject {
@Published var exploreTabNavPath: NavigationPathWrapper<HomeExploreNavigationDestination> = .init()
@Published var activityTabNavPath: NavigationPathWrapper<HomeActivityNavigationDestination> = .init()
@Published var presentedNFT: NFTDisplayInfo?
@Published var requestingRecoveryMPC: MPCWalletMetadataDisplayInfo?

@Published var presentedDomain: DomainPresentationDetails?
@Published var presentedPublicDomain: PublicProfileViewConfiguration?
Expand Down Expand Up @@ -304,6 +305,7 @@ extension HomeTabRouter {
resolvingPrimaryDomainWallet = nil
showingWalletInfo = nil
sendCryptoInitialData = nil
requestingRecoveryMPC = nil
walletViewNavPath.removeAll()
chatTabNavPath.removeAll()
exploreTabNavPath.removeAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ struct HomeTabView: View {
NFTDetailsView(nft: nft)
.pullUpHandler(router)
})
.sheet(item: $router.requestingRecoveryMPC, content: { mpcWalletMetadataDisplayInfo in
MPCRequestRecoveryView(mpcWalletMetadata: mpcWalletMetadataDisplayInfo.walletMetadata)
.pullUpHandler(router)
})
.sheet(isPresented: $router.showingUpdatedToWalletGreetings, content: {
UpdateToWalletGreetingsView()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ private extension HomeWalletActionsView {
icon: { subAction.icon }
)
}

}
} label: {
walletActionButtonView(title: action.title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@ struct MPCActivateWalletEnterView: View, ViewAnalyticsLogger {
let confirmationCallback: (String)->()
var changeEmailCallback: EmptyCallback? = nil
@State private var input = ""
@State private var isPresentingForgotPasswordView = false

var body: some View {
VStack(spacing: isIPSE ? 16 : 24) {
DismissIndicatorView()
headerView()
inputView()
if case .passcode(let resendAction) = dataType {
MPCResendCodeButton(email: email, resendAction: resendAction)
}
subActionView()
actionButtonView()
Spacer()
}
.padding()
.sheet(isPresented: $isPresentingForgotPasswordView) {
MPCForgotPasswordView(isModallyPresented: true)
}
}
}

Expand Down Expand Up @@ -116,6 +118,28 @@ private extension MPCActivateWalletEnterView {
}
}

@ViewBuilder
func subActionView() -> some View {
switch dataType {
case .passcode(let resendAction):
MPCResendCodeButton(email: email, resendAction: resendAction)
case .password:
forgotPasswordButtonView()
}
}

@ViewBuilder
func forgotPasswordButtonView() -> some View {
UDButtonView(text: String.Constants.forgotPasswordTitle.localized(),
style: .large(.ghostPrimary),
callback: forgotPasswordButtonPressed)
}

func forgotPasswordButtonPressed() {
logButtonPressedAnalyticEvents(button: .forgotPassword)
isPresentingForgotPasswordView = true
}

@ViewBuilder
func actionButtonView() -> some View {
UDButtonView(text: String.Constants.confirm.localized(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ private extension MPCActivateWalletView {

#Preview {
MPCActivateWalletView(analyticsName: .mpcActivationOnboarding,
credentials: .init(email: "",
credentials: .init(email: "qq@qq.qq",
password: ""),
code: "",
mpcWalletCreatedCallback: { _ in },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private extension MPCEnterCredentialsView {
logButtonPressedAnalyticEvents(button: .forgotPassword)
forgotPasswordCallback()
} label: {
Text("Forgot password?")
Text(String.Constants.forgotPasswordTitle.localized())
.textAttributes(color: .foregroundAccent,
fontSize: 13,
fontWeight: .medium)
Expand Down Expand Up @@ -205,5 +205,6 @@ extension MPCEnterCredentialsView {
//
// return nav

MPCEnterCredentialsView(analyticsName: .addEmail, credentialsCallback: { _ in })
MPCEnterCredentialsView(analyticsName: .addEmail, credentialsCallback: { _ in },
forgotPasswordCallback: { })
}
Loading

0 comments on commit 05674f0

Please sign in to comment.