diff --git a/unstoppable-ios-app/domains-manager-ios-preview/AppContext/PreviewWalletConnectServiceV2.swift b/unstoppable-ios-app/domains-manager-ios-preview/AppContext/PreviewWalletConnectServiceV2.swift index f8e535601..063c520f6 100644 --- a/unstoppable-ios-app/domains-manager-ios-preview/AppContext/PreviewWalletConnectServiceV2.swift +++ b/unstoppable-ios-app/domains-manager-ios-preview/AppContext/PreviewWalletConnectServiceV2.swift @@ -11,6 +11,8 @@ typealias ResponseV2 = String typealias SessionV2Proxy = String final class WalletConnectServiceV2: WalletConnectServiceV2Protocol { + static let supportedNetworks: [BlockchainType] = [.Ethereum, .Matic] + func sendSignTx(sessions: [WCConnectedAppsStorageV2.SessionProxy], chainId: Int, tx: EthereumTransaction, address: HexAddress, in wallet: UDWallet) async throws -> ResponseV2 { throw NSError() } diff --git a/unstoppable-ios-app/domains-manager-ios-preview/Entities/PreviewDomainItem.swift b/unstoppable-ios-app/domains-manager-ios-preview/Entities/PreviewDomainItem.swift index 0d41c0002..5a7383f80 100644 --- a/unstoppable-ios-app/domains-manager-ios-preview/Entities/PreviewDomainItem.swift +++ b/unstoppable-ios-app/domains-manager-ios-preview/Entities/PreviewDomainItem.swift @@ -14,7 +14,7 @@ struct DomainItem: DomainEntity { func doesRequirePayment() -> Bool { switch self.getBlockchainType() { - case .Ethereum: return true + case .Ethereum, .Base: return true case .Matic: return false } } diff --git a/unstoppable-ios-app/domains-manager-ios/Entities/Mock/MockEntitiesFabric+Domains.swift b/unstoppable-ios-app/domains-manager-ios/Entities/Mock/MockEntitiesFabric+Domains.swift index dd23d5bdc..c66290eca 100644 --- a/unstoppable-ios-app/domains-manager-ios/Entities/Mock/MockEntitiesFabric+Domains.swift +++ b/unstoppable-ios-app/domains-manager-ios/Entities/Mock/MockEntitiesFabric+Domains.swift @@ -39,7 +39,7 @@ extension MockEntitiesFabric { domains.append(domain) } } - + return domains } @@ -105,6 +105,10 @@ extension MockEntitiesFabric { ownerAddress: "123") ] } + + static func mockFirebaseDomainsDisplayInfo() -> [FirebaseDomainDisplayInfo] { + mockFirebaseDomains().map { FirebaseDomainDisplayInfo(firebaseDomain: $0) } + } } } diff --git a/unstoppable-ios-app/domains-manager-ios/Entities/Toast.swift b/unstoppable-ios-app/domains-manager-ios/Entities/Toast.swift index 5e447c066..2cd3515f0 100644 --- a/unstoppable-ios-app/domains-manager-ios/Entities/Toast.swift +++ b/unstoppable-ios-app/domains-manager-ios/Entities/Toast.swift @@ -21,7 +21,6 @@ enum Toast: Hashable { case failedToUpdateProfile case itemSaved(name: String) case itemCopied(name: String) - case parkedDomainsImported(_ domainsCount: Int) case userLoggedOut case communityProfileEnabled case purchaseDomainsDiscountApplied(Int) @@ -61,8 +60,6 @@ enum Toast: Hashable { return String.Constants.nSaved.localized(name) case .itemCopied(let name): return String.Constants.nCopied.localized(name) - case .parkedDomainsImported(let domainsCount): - return String.Constants.pluralNParkedDomainsImported.localized(domainsCount, domainsCount) case .userLoggedOut: return String.Constants.userLoggedOutToastMessage.localized() case .communityProfileEnabled: @@ -76,7 +73,7 @@ enum Toast: Hashable { var secondaryMessage: String? { switch self { - case .walletAddressCopied, .walletAdded, .iCloudBackupRestored, .walletRemoved, .walletDisconnected, .noInternetConnection, .changesConfirmed, .mintingSuccessful, .mintingUnavailable, .updatingRecords, .domainCopied, .failedToRefreshBadges, .itemSaved, .itemCopied, .parkedDomainsImported, .userLoggedOut, .communityProfileEnabled, .purchaseDomainsDiscountApplied, .followedProfileAs: + case .walletAddressCopied, .walletAdded, .iCloudBackupRestored, .walletRemoved, .walletDisconnected, .noInternetConnection, .changesConfirmed, .mintingSuccessful, .mintingUnavailable, .updatingRecords, .domainCopied, .failedToRefreshBadges, .itemSaved, .itemCopied, .userLoggedOut, .communityProfileEnabled, .purchaseDomainsDiscountApplied, .followedProfileAs: return nil case .failedToFetchDomainProfileData: return String.Constants.refresh.localized() @@ -87,7 +84,7 @@ enum Toast: Hashable { var style: Style { switch self { - case .walletAddressCopied, .walletAdded, .iCloudBackupRestored, .walletRemoved, .walletDisconnected, .changesConfirmed, .mintingSuccessful, .domainCopied, .itemSaved, .itemCopied, .parkedDomainsImported, .userLoggedOut, .communityProfileEnabled, .purchaseDomainsDiscountApplied, .followedProfileAs: + case .walletAddressCopied, .walletAdded, .iCloudBackupRestored, .walletRemoved, .walletDisconnected, .changesConfirmed, .mintingSuccessful, .domainCopied, .itemSaved, .itemCopied, .userLoggedOut, .communityProfileEnabled, .purchaseDomainsDiscountApplied, .followedProfileAs: return .success case .noInternetConnection, .updatingRecords, .mintingUnavailable, .failedToFetchDomainProfileData, .failedToUpdateProfile: return .dark @@ -98,7 +95,7 @@ enum Toast: Hashable { var image: UIImage { switch self { - case .walletAddressCopied, .walletAdded, .iCloudBackupRestored, .walletRemoved, .walletDisconnected, .changesConfirmed, .mintingSuccessful, .domainCopied, .itemSaved, .itemCopied, .parkedDomainsImported, .userLoggedOut, .communityProfileEnabled, .purchaseDomainsDiscountApplied, .followedProfileAs: + case .walletAddressCopied, .walletAdded, .iCloudBackupRestored, .walletRemoved, .walletDisconnected, .changesConfirmed, .mintingSuccessful, .domainCopied, .itemSaved, .itemCopied, .userLoggedOut, .communityProfileEnabled, .purchaseDomainsDiscountApplied, .followedProfileAs: return .checkCircleWhite case .noInternetConnection: return .connectionOffIcon @@ -147,8 +144,6 @@ enum Toast: Hashable { return lhsName == rhsName case (.itemCopied(let lhsName), .itemCopied(let rhsName)): return lhsName == rhsName - case (.parkedDomainsImported(let lhsCount), .parkedDomainsImported(let rhsCount)): - return lhsCount == rhsCount case (.userLoggedOut, .userLoggedOut): return true case (.communityProfileEnabled, .communityProfileEnabled): diff --git a/unstoppable-ios-app/domains-manager-ios/Extensions/Extension-String+Preview.swift b/unstoppable-ios-app/domains-manager-ios/Extensions/Extension-String+Preview.swift index 8fecfb9d2..3a7fc3474 100644 --- a/unstoppable-ios-app/domains-manager-ios/Extensions/Extension-String+Preview.swift +++ b/unstoppable-ios-app/domains-manager-ios/Extensions/Extension-String+Preview.swift @@ -459,7 +459,8 @@ extension String { static let settingsAppearanceChooseTheme = "SETTINGS_APPEARANCE_CHOOSE_THEME" static let youAreUnstoppable = "YOU_ARE_UNSTOPPABLE" static let feedbackEmailSubject = "FEEDBACK_EMAIL_SUBJECT" - + static let viewOrMoveVaultedDomains = "VIEW_OR_MOVE_VAULTED_DOMAINS" + // Wallets list static let manageICloudBackups = "MANAGE_ICLOUD_BACKUPS" static let restoreFromICloudBackup = "RESTORE_FROM_ICLOUD_BACKUP" @@ -1271,7 +1272,7 @@ extension String { static let reviewTxAgain = "REVIEW_TX_AGAIN" static let confirmAndSend = "CONFIRM_AND_SEND" - static let parkedDomains = "PARKED_DOMAINS" + static let domainVault = "DOMAIN_VAULT" static let backedUp = "BACKED_UP" static let backUp = "BACK_UP" static let setAsPrimaryDomain = "SET_AS_PRIMARY_DOMAIN" diff --git a/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundInAppViewPresenter.swift b/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundInAppViewPresenter.swift index da291a1cf..ce007cb80 100644 --- a/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundInAppViewPresenter.swift +++ b/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundInAppViewPresenter.swift @@ -14,7 +14,7 @@ final class ParkedDomainsFoundInAppViewPresenter: ParkedDomainsFoundViewPresente override var title: String { String.Constants.pluralWeFoundNDomains.localized(domains.count, domains.count) } - override var progress: Double? { 1 } + override var progress: Double? { nil } init(view: ParkedDomainsFoundViewProtocol, domains: [FirebaseDomainDisplayInfo], diff --git a/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewController.swift b/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewController.swift index 84e558b2b..abaca57df 100644 --- a/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewController.swift +++ b/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewController.swift @@ -8,77 +8,37 @@ import UIKit @MainActor -protocol ParkedDomainsFoundViewProtocol: BaseCollectionViewControllerProtocol & ViewWithDashesProgress{ - func applySnapshot(_ snapshot: ParkedDomainsFoundSnapshot, animated: Bool) +protocol ParkedDomainsFoundViewProtocol: ViewWithDashesProgress{ + func setWith(email: String, numberOfDomainsFound: Int) } -typealias ParkedDomainsFoundDataSource = UICollectionViewDiffableDataSource -typealias ParkedDomainsFoundSnapshot = NSDiffableDataSourceSnapshot - @MainActor final class ParkedDomainsFoundViewController: BaseViewController { - @IBOutlet weak var collectionView: UICollectionView! + @IBOutlet private weak var emailLabel: UILabel! + @IBOutlet private weak var titleLabel: UDTitleLabel! @IBOutlet private weak var importButton: MainButton! - var cellIdentifiers: [UICollectionViewCell.Type] { [ParkedDomainCell.self] } var presenter: ParkedDomainsFoundViewPresenterProtocol! - private var dataSource: ParkedDomainsFoundDataSource! - override var prefersLargeTitles: Bool { true } - override var largeTitleAlignment: NSTextAlignment { .center } - override var largeTitleIcon: UIImage? { .checkmark } - override var largeTitleIconTintColor: UIColor { .foregroundSuccess } - override var scrollableContentYOffset: CGFloat? { 10 } - override var adjustLargeTitleFontSizeForSmallerDevice: Bool { true } override var analyticsName: Analytics.ViewName { .parkedDomainsList } override func viewDidLoad() { super.viewDidLoad() - configureCollectionView() setup() presenter.viewDidLoad() } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - -// cNavigationBar?.setBackButton(hidden: true) - } } // MARK: - ParkedDomainsFoundViewProtocol extension ParkedDomainsFoundViewController: ParkedDomainsFoundViewProtocol { var progress: Double? { presenter.progress } - func applySnapshot(_ snapshot: ParkedDomainsFoundSnapshot, animated: Bool) { - dataSource.apply(snapshot, animatingDifferences: animated) - } -} - -// MARK: - UICollectionViewDelegate -extension ParkedDomainsFoundViewController: UICollectionViewDelegate { - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let item = dataSource.itemIdentifier(for: indexPath) else { return } - switch item { - case .parkedDomain(let domain): - logAnalytic(event: .domainPressed, parameters: [.domainName: domain.name]) - } - presenter.didSelectItem(item) - } - - func scrollViewDidScroll(_ scrollView: UIScrollView) { - cNavigationController?.underlyingScrollViewDidScroll(scrollView) - } - - func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { - if !decelerate { - cNavigationController?.underlyingScrollViewDidFinishScroll(scrollView) - } - } - - func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { - cNavigationController?.underlyingScrollViewDidFinishScroll(scrollView) + func setWith(email: String, numberOfDomainsFound: Int) { + emailLabel.setAttributedTextWith(text: email, + font: .currentFont(withSize: 16, weight: .medium), + textColor: .foregroundSuccess) + titleLabel.setTitle(String.Constants.pluralNParkedDomainsImported.localized(numberOfDomainsFound, numberOfDomainsFound)) } } @@ -94,93 +54,23 @@ private extension ParkedDomainsFoundViewController { private extension ParkedDomainsFoundViewController { func setup() { addProgressDashesView() - setupCollectionView() - title = presenter.title importButton.setTitle(String.Constants.viewVaultedDomains.localized(), image: nil) } - func setupCollectionView() { - collectionView.delegate = self - collectionView.collectionViewLayout = buildLayout() - collectionView.contentInset.top = 177 - collectionView.register(CollectionTextHeaderReusableView.self, - forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, - withReuseIdentifier: CollectionTextHeaderReusableView.reuseIdentifier) - - configureDataSource() - } - - func configureDataSource() { - dataSource = ParkedDomainsFoundDataSource.init(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in - switch item { - case .parkedDomain(let domain): - let cell = collectionView.dequeueCellOfType(ParkedDomainCell.self, forIndexPath: indexPath) - - cell.setWith(domain: domain) - return cell - } - }) - - dataSource.supplementaryViewProvider = { collectionView, elementKind, indexPath in - let view = collectionView.dequeueReusableSupplementaryView(ofKind: elementKind, - withReuseIdentifier: CollectionTextHeaderReusableView.reuseIdentifier, - for: indexPath) as! CollectionTextHeaderReusableView - - view.setHeader(String.Constants.parkedDomainsFound.localized()) - - return view - } - } - - func buildLayout() -> UICollectionViewLayout { - let spacing: CGFloat = UICollectionView.SideOffset - - let config = UICollectionViewCompositionalLayoutConfiguration() - config.interSectionSpacing = spacing - - let layout = UICollectionViewCompositionalLayout(sectionProvider: { - (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in - - let layoutSection: NSCollectionLayoutSection - let sectionHeaderHeight = CollectionTextHeaderReusableView.Height - - layoutSection = .flexibleListItemSection() - layoutSection.contentInsets = NSDirectionalEdgeInsets(top: 1, - leading: spacing + 1, - bottom: 1, - trailing: spacing + 1) - let background = NSCollectionLayoutDecorationItem.background(elementKind: CollectionReusableRoundedBackground.reuseIdentifier) - background.contentInsets.top = sectionHeaderHeight - layoutSection.decorationItems = [background] - - - let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), - heightDimension: .absolute(sectionHeaderHeight)) - let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, - elementKind: UICollectionView.elementKindSectionHeader, - alignment: .top) - layoutSection.boundarySupplementaryItems = [header] - - - - - return layoutSection - - }, configuration: config) - layout.register(CollectionReusableRoundedBackground.self, forDecorationViewOfKind: CollectionReusableRoundedBackground.reuseIdentifier) - - return layout - } } -// MARK: - Collection elements -extension ParkedDomainsFoundViewController { - enum Section: Int, Hashable { - case main - } - - enum Item: Hashable { - case parkedDomain(_ domain: FirebaseDomainDisplayInfo) - } +@available(iOS 17.0, *) +#Preview { + let vc = ParkedDomainsFoundViewController.nibInstance() + let manager = PreviewLoginManager() + let presenter = ParkedDomainsFoundInAppViewPresenter(view: vc, + domains: MockEntitiesFabric.Domains.mockFirebaseDomainsDisplayInfo(), + loginFlowManager: manager) + vc.presenter = presenter + return vc +} + +private final class PreviewLoginManager: LoginFlowManager { + func handle(action: LoginFlowNavigationController.Action) async throws { } } diff --git a/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewController.xib b/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewController.xib index ae2f5cf37..92ab931e1 100644 --- a/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewController.xib +++ b/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewController.xib @@ -1,10 +1,9 @@ - - + + - - + @@ -12,8 +11,9 @@ - + + @@ -22,27 +22,6 @@ - - - - - - - - - - - - - - - - - - - - - @@ -59,32 +38,45 @@ + + + + + + + + + + - - - - - - + - + + - - - - + + + - - - + diff --git a/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewPresenter.swift b/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewPresenter.swift index 631e8b278..acc0da49b 100644 --- a/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewPresenter.swift +++ b/unstoppable-ios-app/domains-manager-ios/Modules/ParkedDomains/ParkedDomainsFound/ParkedDomainsFoundViewPresenter.swift @@ -11,7 +11,6 @@ protocol ParkedDomainsFoundViewPresenterProtocol: BasePresenterProtocol { var title: String { get } var progress: Double? { get } - func didSelectItem(_ item: ParkedDomainsFoundViewController.Item) func importButtonPressed() } @@ -38,47 +37,21 @@ class ParkedDomainsFoundViewPresenter { // MARK: - ParkedDomainsFoundViewPresenterProtocol extension ParkedDomainsFoundViewPresenter: ParkedDomainsFoundViewPresenterProtocol { func viewDidLoad() { - showData() Task { @MainActor in + view?.setWith(email: webUser?.email ?? "", numberOfDomainsFound: domains.count) view?.setDashesProgress(progress) } } - - @MainActor - func didSelectItem(_ item: ParkedDomainsFoundViewController.Item) { - UDVibration.buttonTap.vibrate() - guard let view else { return } - - switch item { - case .parkedDomain(let domain): - switch domain.parkingStatus { - case .parkedButExpiresSoon(let expiresDate): - appContext.pullUpViewService.showParkedDomainExpiresSoonPullUp(in: view, expiresDate: expiresDate) - case .parkingTrial(let expiresDate): - appContext.pullUpViewService.showParkedDomainTrialExpiresPullUp(in: view, expiresDate: expiresDate) - case .parked, .freeParking: - appContext.pullUpViewService.showParkedDomainInfoPullUp(in: view) - case .parkingExpired: - appContext.pullUpViewService.showParkedDomainExpiredPullUp(in: view) - default: - return - } - } - } } -// MARK: - Private functions +// MARK: - Private methods private extension ParkedDomainsFoundViewPresenter { - func showData() { - Task { - var snapshot = ParkedDomainsFoundSnapshot() - - snapshot.appendSections([.main]) - snapshot.appendItems(domains.map({ ParkedDomainsFoundViewController.Item.parkedDomain($0) })) - - await view?.applySnapshot(snapshot, animated: true) + var webUser: FirebaseUser? { + for profile in appContext.userProfilesService.profiles { + if case .webAccount(let firebaseUser) = profile { + return firebaseUser + } } + return nil } } - - diff --git a/unstoppable-ios-app/domains-manager-ios/Modules/QRScanner/QRScannerViewPresenter.swift b/unstoppable-ios-app/domains-manager-ios/Modules/QRScanner/QRScannerViewPresenter.swift index 046de2706..c5fff4567 100644 --- a/unstoppable-ios-app/domains-manager-ios/Modules/QRScanner/QRScannerViewPresenter.swift +++ b/unstoppable-ios-app/domains-manager-ios/Modules/QRScanner/QRScannerViewPresenter.swift @@ -18,7 +18,6 @@ protocol QRScannerViewPresenterProtocol: BasePresenterProtocol { func didSelectBlockchainType(_ blockchainType: BlockchainType) } -@MainActor final class QRScannerViewPresenter: ViewAnalyticsLogger { internal weak var view: QRScannerViewProtocol? @@ -164,15 +163,18 @@ extension QRScannerViewPresenter: WalletConnectServiceConnectionListener { // MARK: - Private functions private extension QRScannerViewPresenter { func setBlockchainTypePicker() { - view?.setBlockchainTypeSelectionWith(availableTypes: WalletConnectServiceV2.supportedNetworks, selectedType: blockchainType) + Task { @MainActor in + view?.setBlockchainTypeSelectionWith(availableTypes: WalletConnectServiceV2.supportedNetworks, selectedType: blockchainType) + } } func setSelected(wallet: WalletEntity) { let wallets = walletsDataService.wallets self.selectedWallet = wallet - - view?.setWith(wallet: wallet, - isSelectable: wallets.count > 1) + Task { @MainActor in + view?.setWith(wallet: wallet, + isSelectable: wallets.count > 1) + } } func setSelectedWalletInfo() { @@ -183,7 +185,9 @@ private extension QRScannerViewPresenter { func showNumberOfAppsConnected() { let appsConnected = walletConnectServiceV2.getConnectedApps() - view?.setWith(appsConnected: appsConnected.count) + Task { @MainActor in + view?.setWith(appsConnected: appsConnected.count) + } } func getWCConnectionRequest(for code: QRCode) async throws -> WCRequest { diff --git a/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsProfileTileView.swift b/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsProfileTileView.swift index 5b0b7d739..32115d8f0 100644 --- a/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsProfileTileView.swift +++ b/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsProfileTileView.swift @@ -172,7 +172,7 @@ private extension SettingsProfileTileView { case .wallet(let wallet): return wallet.displayName case .webAccount: - return String.Constants.parkedDomains.localized() + return String.Constants.domainVault.localized() } } diff --git a/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsProfilesView.swift b/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsProfilesView.swift index 419c47aee..f27511f70 100644 --- a/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsProfilesView.swift +++ b/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsProfilesView.swift @@ -22,24 +22,69 @@ struct SettingsProfilesView: View, ViewAnalyticsLogger { var body: some View { LazyVGrid(columns: gridColumns, spacing: 16) { ForEach(profiles, id: \.id) { profile in - Button { - logButtonPressedAnalyticEvents(button: .walletInList) - UDVibration.buttonTap.vibrate() - switch profile { - case .wallet(let wallet): - tabRouter.walletViewNavPath.append(.walletDetails(wallet)) - case .webAccount: - return - } - } label: { - SettingsProfileTileView(profile: profile) - } - .buttonStyle(.plain) + tileViewForProfile(profile) } } } } +// MARK: - Private methods +private extension SettingsProfilesView { + @ViewBuilder + func tileViewForProfile(_ profile: UserProfile) -> some View { + switch profile { + case .wallet(let wallet): + titleViewForWalletProfile(profile, wallet: wallet) + case .webAccount(let firebaseUser): + titleViewForFirebaseUserProfile(profile, + firebaseUser: firebaseUser) + } + } + + @ViewBuilder + func titleViewForWalletProfile(_ profile: UserProfile, + wallet: WalletEntity) -> some View { + Button { + logButtonPressedAnalyticEvents(button: .walletInList) + UDVibration.buttonTap.vibrate() + tabRouter.walletViewNavPath.append(.walletDetails(wallet)) + } label: { + SettingsProfileTileView(profile: profile) + } + .buttonStyle(.plain) + } + + @ViewBuilder + func titleViewForFirebaseUserProfile(_ profile: UserProfile, + firebaseUser: FirebaseUser) -> some View { + Menu { + Button(role: .destructive) { + askToLogOut() + } label: { + Label(String.Constants.logOut.localized(), systemImage: "rectangle.portrait.and.arrow.right") + } + } label: { + SettingsProfileTileView(profile: profile) + } + .onButtonTap { + logButtonPressedAnalyticEvents(button: .logOut) + } + } + + func askToLogOut() { + Task { @MainActor in + guard let topVC = appContext.coreAppCoordinator.topVC else { return } + + do { + try await appContext.pullUpViewService.showLogoutConfirmationPullUp(in: topVC) + await topVC.dismissPullUpMenu() + try await appContext.authentificationService.verifyWith(uiHandler: topVC, purpose: .confirm) + appContext.firebaseParkedDomainsAuthenticationService.logOut() + appContext.toastMessageService.showToast(.userLoggedOut, isSticky: false) + } + } + } +} #Preview { SettingsProfilesView(profiles: [MockEntitiesFabric.Profile.createWalletProfile(), diff --git a/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsView.swift b/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsView.swift index 0f8ba9ae1..02db0bd78 100644 --- a/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsView.swift +++ b/unstoppable-ios-app/domains-manager-ios/Modules/Settings/SettingsView.swift @@ -33,9 +33,6 @@ struct SettingsView: View, ViewAnalyticsLogger { .navigationTitle(String.Constants.settings.localized()) .navigationBarTitleDisplayMode(.large) .viewPullUp($pullUp) - .toolbar { - ToolbarItem(placement: .topBarTrailing, content: topBarButton) - } .onAppear(perform: onAppear) } @@ -78,69 +75,7 @@ private extension SettingsView { Spacer() } } - - var webUser: FirebaseUser? { - for profile in profiles { - if case .webAccount(let firebaseUser) = profile { - return firebaseUser - } - } - return nil - } - - @ViewBuilder - func topBarButton() -> some View { - if let webUser { - webUserActionButton(webUser) - } else { - loginButton() - } - } - - @ViewBuilder - func webUserActionButton(_ webUser: FirebaseUser) -> some View { - Menu { - Button(role: .destructive) { - askToLogOut() - } label: { - Label(String.Constants.logOut.localized(), systemImage: "rectangle.portrait.and.arrow.right") - } - } label: { - Image.peopleCircleIcon - .resizable() - .squareFrame(28) - .foregroundStyle(Color.foregroundDefault) - } - .onButtonTap { - logButtonPressedAnalyticEvents(button: .logOut) - } - } - - func askToLogOut() { - Task { @MainActor in - guard let topVC = appContext.coreAppCoordinator.topVC else { return } - - do { - try await appContext.pullUpViewService.showLogoutConfirmationPullUp(in: topVC) - await topVC.dismissPullUpMenu() - try await appContext.authentificationService.verifyWith(uiHandler: topVC, purpose: .confirm) - appContext.firebaseParkedDomainsAuthenticationService.logOut() - appContext.toastMessageService.showToast(.userLoggedOut, isSticky: false) - } - } - } - - @ViewBuilder - func loginButton() -> some View { - Button { - UDVibration.buttonTap.vibrate() - logButtonPressedAnalyticEvents(button: .logIn) - pullUp = .default(.loginOptionsSelectionPullUp(selectionCallback: didSelectToAuthWith)) - } label: { - topActinTextView(text: String.Constants.login.localized()) - } - } - + @ViewBuilder func topActinTextView(text: String) -> some View { Text(text) @@ -392,11 +327,28 @@ private extension SettingsView { otherItemsList() } + var settingsItemsToShow: [SettingsItems] { + var items = SettingsItems.allCases + if webUser != nil { + items.removeAll(where: { $0 == .viewVaulted }) + } + return items + } + + var webUser: FirebaseUser? { + for profile in profiles { + if case .webAccount(let firebaseUser) = profile { + return firebaseUser + } + } + return nil + } + @ViewBuilder func otherItemsList() -> some View { UDCollectionSectionBackgroundView { VStack(alignment: .center, spacing: 0) { - ForEach(SettingsItems.allCases, id: \.self) { moreItem in + ForEach(settingsItemsToShow, id: \.self) { moreItem in listViewFor(otherItem: moreItem) } } @@ -432,6 +384,8 @@ private extension SettingsView { openFeedbackMailForm() case .legal: pullUp = .default(.legalSelectionPullUp(selectionCallback: didSelectLegalType)) + case .viewVaulted: + pullUp = .default(.loginOptionsSelectionPullUp(selectionCallback: didSelectToAuthWith)) } } } @@ -707,7 +661,7 @@ private extension SettingsView { } enum SettingsItems: CaseIterable { - case rateUs, learn, twitter, support, legal + case rateUs, learn, viewVaulted, twitter, support, legal var title: String { switch self { @@ -721,6 +675,8 @@ private extension SettingsView { return String.Constants.settingsSupportNFeedback.localized() case .legal: return String.Constants.settingsLegal.localized() + case .viewVaulted: + return String.Constants.viewOrMoveVaultedDomains.localized() } } @@ -736,6 +692,8 @@ private extension SettingsView { return .settingsIconFeedback case .legal: return .settingsIconLegal + case .viewVaulted: + return .vaultSafeIcon } } @@ -751,6 +709,8 @@ private extension SettingsView { return .settingsSupport case .legal: return .settingsLegal + case .viewVaulted: + return .viewVaultedDomains } } } diff --git a/unstoppable-ios-app/domains-manager-ios/Services/AnalyticsService/AnalyticsServiceEnvironment.swift b/unstoppable-ios-app/domains-manager-ios/Services/AnalyticsService/AnalyticsServiceEnvironment.swift index b2323397f..c57b5bb4f 100644 --- a/unstoppable-ios-app/domains-manager-ios/Services/AnalyticsService/AnalyticsServiceEnvironment.swift +++ b/unstoppable-ios-app/domains-manager-ios/Services/AnalyticsService/AnalyticsServiceEnvironment.swift @@ -322,7 +322,7 @@ extension Analytics { case editProfile, manageDomain, shareLink, saveAsImage, createNFCTag // Settings - case settingsWallets, settingsSecurity, settingsTheme, settingsLearn, settingsTwitter, settingsSupport, settingsLegal, settingsTestnet, settingsHomeScreen, settingsRateUs, settingsWebsiteAccount + case settingsWallets, settingsSecurity, settingsTheme, settingsLearn, settingsTwitter, settingsSupport, settingsLegal, settingsTestnet, settingsHomeScreen, settingsRateUs, settingsWebsiteAccount, viewVaultedDomains // Security settings case securitySettingsPasscode, securitySettingsBiometric, securitySettingsRequireSAWhenOpen diff --git a/unstoppable-ios-app/domains-manager-ios/Services/PullUp/PullUpViewService.swift b/unstoppable-ios-app/domains-manager-ios/Services/PullUp/PullUpViewService.swift index af5955e72..5b58385a6 100644 --- a/unstoppable-ios-app/domains-manager-ios/Services/PullUp/PullUpViewService.swift +++ b/unstoppable-ios-app/domains-manager-ios/Services/PullUp/PullUpViewService.swift @@ -476,68 +476,7 @@ extension PullUpViewService: PullUpViewServiceProtocol { showOrUpdate(in: viewController, pullUp: .logOutConfirmation, contentView: selectionView, height: selectionViewHeight, closedCallback: { completion(.failure(PullUpError.dismissed)) }) } } - - func showParkedDomainInfoPullUp(in viewController: UIViewController) { - let selectionViewHeight: CGFloat = 304 - let selectionView = PullUpSelectionView(configuration: .init(title: .text(String.Constants.parkedDomainInfoPullUpTitle.localized()), - contentAlignment: .center, - icon: .init(icon: .parkingIcon24, - size: .small), - subtitle: .label(.text(String.Constants.parkedDomainInfoPullUpSubtitle.localized())), - cancelButton: .gotItButton()), - items: PullUpSelectionViewEmptyItem.allCases) - - presentPullUpView(in: viewController, pullUp: .parkedDomainInfo, contentView: selectionView, isDismissAble: true, height: selectionViewHeight) - } - - func showParkedDomainTrialExpiresPullUp(in viewController: UIViewController, - expiresDate: Date) { - let expiresDateString = DateFormattingService.shared.formatParkingExpiresDate(expiresDate) - - let selectionViewHeight: CGFloat = 380 - let selectionView = PullUpSelectionView(configuration: .init(title: .text(String.Constants.parkedDomainTrialExpiresInfoPullUpTitle.localized(expiresDateString)), - contentAlignment: .center, - icon: .init(icon: .warningIcon, - size: .small, - tintColor: .foregroundWarning), - subtitle: .label(.text(String.Constants.parkedDomainTrialExpiresInfoPullUpSubtitle.localized())), - cancelButton: .gotItButton()), - items: PullUpSelectionViewEmptyItem.allCases) - - presentPullUpView(in: viewController, pullUp: .parkedDomainTrialExpiresInfo, contentView: selectionView, isDismissAble: true, height: selectionViewHeight) - } - - func showParkedDomainExpiresSoonPullUp(in viewController: UIViewController, - expiresDate: Date) { - let expiresDateString = DateFormattingService.shared.formatParkingExpiresDate(expiresDate) - - let selectionViewHeight: CGFloat = 328 - let selectionView = PullUpSelectionView(configuration: .init(title: .text(String.Constants.parkedDomainExpiresSoonPullUpTitle.localized(expiresDateString)), - contentAlignment: .center, - icon: .init(icon: .warningIcon, - size: .small, - tintColor: .foregroundWarning), - subtitle: .label(.text(String.Constants.parkedDomainExpiresSoonPullUpSubtitle.localized())), - cancelButton: .gotItButton()), - items: PullUpSelectionViewEmptyItem.allCases) - - presentPullUpView(in: viewController, pullUp: .parkedDomainExpiresSoonInfo, contentView: selectionView, isDismissAble: true, height: selectionViewHeight) - } - - func showParkedDomainExpiredPullUp(in viewController: UIViewController) { - let selectionViewHeight: CGFloat = 328 - let selectionView = PullUpSelectionView(configuration: .init(title: .text(String.Constants.parkedDomainExpiredInfoPullUpTitle.localized()), - contentAlignment: .center, - icon: .init(icon: .warningIcon, - size: .small, - tintColor: .foregroundWarning), - subtitle: .label(.text(String.Constants.parkedDomainExpiredInfoPullUpSubtitle.localized())), - cancelButton: .gotItButton()), - items: PullUpSelectionViewEmptyItem.allCases) - - presentPullUpView(in: viewController, pullUp: .parkedDomainExpiredInfo, contentView: selectionView, isDismissAble: true, height: selectionViewHeight) - } - + func showApplePayRequiredPullUp(in viewController: UIViewController) { let selectionViewHeight: CGFloat = 304 let selectionView = PullUpSelectionView(configuration: .init(title: .text(String.Constants.applePayRequiredPullUpTitle.localized()), diff --git a/unstoppable-ios-app/domains-manager-ios/Services/PullUp/PullUpViewServiceProtocol.swift b/unstoppable-ios-app/domains-manager-ios/Services/PullUp/PullUpViewServiceProtocol.swift index 38d840774..e41d1ae59 100644 --- a/unstoppable-ios-app/domains-manager-ios/Services/PullUp/PullUpViewServiceProtocol.swift +++ b/unstoppable-ios-app/domains-manager-ios/Services/PullUp/PullUpViewServiceProtocol.swift @@ -40,12 +40,6 @@ protocol PullUpViewServiceProtocol { func showChooseCoinVersionPullUp(for coin: CoinRecord, in viewController: UIViewController) async throws -> CoinVersionSelectionResult func showLogoutConfirmationPullUp(in viewController: UIViewController) async throws - func showParkedDomainInfoPullUp(in viewController: UIViewController) - func showParkedDomainTrialExpiresPullUp(in viewController: UIViewController, - expiresDate: Date) - func showParkedDomainExpiresSoonPullUp(in viewController: UIViewController, - expiresDate: Date) - func showParkedDomainExpiredPullUp(in viewController: UIViewController) func showApplePayRequiredPullUp(in viewController: UIViewController) func showWalletsNumberLimitReachedPullUp(in viewController: UIViewController, maxNumberOfWallets: Int) async diff --git a/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultSafeIcon.imageset/Contents.json b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultSafeIcon.imageset/Contents.json index 330a33f3b..150f3488d 100644 --- a/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultSafeIcon.imageset/Contents.json +++ b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultSafeIcon.imageset/Contents.json @@ -10,6 +10,7 @@ "version" : 1 }, "properties" : { + "preserves-vector-representation" : true, "template-rendering-intent" : "template" } } diff --git a/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultedDomainsFoundIllustration.imageset/Contents.json b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultedDomainsFoundIllustration.imageset/Contents.json new file mode 100644 index 000000000..7e35bbe13 --- /dev/null +++ b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultedDomainsFoundIllustration.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "vaultedDomainsFoundIllustration.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultedDomainsFoundIllustration.imageset/vaultedDomainsFoundIllustration.pdf b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultedDomainsFoundIllustration.imageset/vaultedDomainsFoundIllustration.pdf new file mode 100644 index 000000000..d0e0991e4 Binary files /dev/null and b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Assets.xcassets/Common/vaultedDomainsFoundIllustration.imageset/vaultedDomainsFoundIllustration.pdf differ diff --git a/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Localization/en.lproj/Localizable.strings b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Localization/en.lproj/Localizable.strings index 45c2316a9..e36fcc7d9 100644 --- a/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Localization/en.lproj/Localizable.strings +++ b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Localization/en.lproj/Localizable.strings @@ -349,6 +349,7 @@ "SETTINGS_APPEARANCE_CHOOSE_THEME" = "Choose theme"; "YOU_ARE_UNSTOPPABLE" = "You are Unstoppable!"; "FEEDBACK_EMAIL_SUBJECT" = "Unstoppable Domains App Feedback - iOS (%@)"; +"VIEW_OR_MOVE_VAULTED_DOMAINS" = "View or move vaulted domains"; // Wallets list "MANAGE_ICLOUD_BACKUPS" = "Manage iCloud backups"; @@ -1165,7 +1166,7 @@ More tabs are coming in the next updates."; "REVIEW_TX_AGAIN" = "Review Transaction Again"; "CONFIRM_AND_SEND" = "Confirm & Send"; -"PARKED_DOMAINS" = "Parked domains"; +"DOMAIN_VAULT" = "Domain Vault"; "BACKED_UP" = "Backed up"; "BACK_UP" = "Back up"; "SET_AS_PRIMARY_DOMAIN" = "Set as primary domain"; diff --git a/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Localization/en.lproj/Localizable.stringsdict b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Localization/en.lproj/Localizable.stringsdict index d37b19776..eb0bbf73e 100644 --- a/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Localization/en.lproj/Localizable.stringsdict +++ b/unstoppable-ios-app/domains-manager-ios/SupportingFiles/Localization/en.lproj/Localizable.stringsdict @@ -317,7 +317,7 @@ SDICT:N_PARKED_DOMAINS_IMPORTED NSStringLocalizedFormatKey - %d %#@domain@ from Unstoppable Vault imported + %d %#@domain@ found in your Domain Vault domain NSStringFormatSpecTypeKey diff --git a/unstoppable-ios-app/domains-manager-ios/SwiftUI/ViewModifiers/ViewPullUp/ViewPullUpDefaultConfiguration.swift b/unstoppable-ios-app/domains-manager-ios/SwiftUI/ViewModifiers/ViewPullUp/ViewPullUpDefaultConfiguration.swift index 11b5cd2b8..ba5c1f7cb 100644 --- a/unstoppable-ios-app/domains-manager-ios/SwiftUI/ViewModifiers/ViewPullUp/ViewPullUpDefaultConfiguration.swift +++ b/unstoppable-ios-app/domains-manager-ios/SwiftUI/ViewModifiers/ViewPullUp/ViewPullUpDefaultConfiguration.swift @@ -470,8 +470,8 @@ extension ViewPullUpDefaultConfiguration { static func loginOptionsSelectionPullUp(selectionCallback: @escaping (LoginProvider)->()) -> ViewPullUpDefaultConfiguration { var selectedItem: LoginProvider? - return .init(title: .text(String.Constants.loginWithWebTitle.localized()), - subtitle: .label(.text(String.Constants.loginWithWebSubtitle.localized())), + return .init(icon: .init(icon: .vaultSafeIcon, size: .large), + title: .text(String.Constants.viewOrMoveVaultedDomains.localized()), items: LoginProvider.allCases, itemSelectedCallback: { item in selectedItem = item as? LoginProvider