From 4c156c3fae52a89ce0f520643c4cbbee60948f0b Mon Sep 17 00:00:00 2001 From: gemdev111 Date: Mon, 28 Jul 2025 17:35:51 +0300 Subject: [PATCH 1/6] Refactor sheet presentation logic in wallet scene Introduced WalletSceneSheetType to unify and simplify sheet presentation state management in WalletSceneViewModel. Updated WalletNavigationStack to use the new enum for presenting sheets, reducing multiple state variables to a single source of truth and improving code maintainability. --- .../Sources/Types/WalletSceneSheetType.swift | 84 ++++++++++++++++++ .../ViewModels/WalletSceneViewModel.swift | 22 ++--- .../Wallet/WalletNavigationStack.swift | 85 +++++++++---------- 3 files changed, 135 insertions(+), 56 deletions(-) create mode 100644 Features/WalletTab/Sources/Types/WalletSceneSheetType.swift diff --git a/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift b/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift new file mode 100644 index 000000000..3cd288f53 --- /dev/null +++ b/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift @@ -0,0 +1,84 @@ +// Copyright (c). Gem Wallet. All rights reserved. + +import Foundation +import InfoSheet +import Primitives +import SwiftUI + +public enum WalletSceneSheetType: Identifiable, Sendable { + case wallets + case selectAssetType(SelectAssetType) + case info(InfoSheetType) + case url(URL) + case transferData(TransferData) + case perpetualRecipientData(PerpetualRecipientData) + + public var id: String { + switch self { + case .wallets: "wallets" + case let .selectAssetType(type): "select-asset-type-\(type.id)" + case let .info(type): "info-\(type.id)" + case let .url(url): "url-\(url)" + case let .transferData(data): "transfer-data-\(data.id)" + case let .perpetualRecipientData(data): "perpetual-recipient-data-\(data.asset.id.identifier)" + } + } +} + +// MARK: - Binding extensions + +extension Binding where Value == WalletSceneSheetType? { + public var selectAssetType: Binding { + Binding( + get: { + if case .selectAssetType(let type) = wrappedValue { + return type + } + return nil + }, + set: { newValue in + wrappedValue = newValue.map { .selectAssetType($0) } + } + ) + } + + public var transferData: Binding { + Binding( + get: { + if case .transferData(let data) = wrappedValue { + return data + } + return nil + }, + set: { newValue in + wrappedValue = newValue.map { .transferData($0) } + } + ) + } + + public var perpetualRecipientData: Binding { + Binding( + get: { + if case .perpetualRecipientData(let data) = wrappedValue { + return data + } + return nil + }, + set: { newValue in + wrappedValue = newValue.map { .perpetualRecipientData($0) } + } + ) + } + + var wallets: Binding { + Binding( + get: { + if case .wallets = wrappedValue { return true } + return false + }, + set: { newValue in + wrappedValue = newValue ? .wallets : nil + } + ) + } +} diff --git a/Features/WalletTab/Sources/ViewModels/WalletSceneViewModel.swift b/Features/WalletTab/Sources/ViewModels/WalletSceneViewModel.swift index 0a9b2d2c5..930b7456d 100644 --- a/Features/WalletTab/Sources/ViewModels/WalletSceneViewModel.swift +++ b/Features/WalletTab/Sources/ViewModels/WalletSceneViewModel.swift @@ -35,14 +35,8 @@ public final class WalletSceneViewModel: Sendable { public var assets: [AssetData] = [] public var banners: [Banner] = [] - // TODO: - separate presenting sheet state logic to separate type public var isPresentingSelectedAssetInput: Binding - public var isPresentingWallets = false - public var isPresentingSelectAssetType: SelectAssetType? - public var isPresentingInfoSheet: InfoSheetType? - public var isPresentingUrl: URL? = nil - public var isPresentingTransferData: TransferData? - public var isPresentingPerpetualRecipientData: PerpetualRecipientData? + public var isPresentingSheet: WalletSceneSheetType? public var isLoadingAssets: Bool = false @@ -129,11 +123,11 @@ extension WalletSceneViewModel { } public func onSelectWalletBar() { - isPresentingWallets.toggle() + isPresentingSheet = .wallets } public func onSelectManage() { - isPresentingSelectAssetType = .manage + isPresentingSheet = .selectAssetType(.manage) } func onHeaderAction(type: HeaderButtonType) { @@ -144,7 +138,7 @@ extension WalletSceneViewModel { case .swap, .more, .stake, .deposit, .withdraw: fatalError() } - isPresentingSelectAssetType = selectType + isPresentingSheet = .selectAssetType(selectType) } func onCloseBanner(banner: Banner) { @@ -152,7 +146,7 @@ extension WalletSceneViewModel { } func onSelectWatchWalletInfo() { - isPresentingInfoSheet = .watchWallet + isPresentingSheet = .info(.watchWallet) } func onBannerAction(banner: Banner) { @@ -167,7 +161,9 @@ extension WalletSceneViewModel { try await handleBanner(action: action) } } - isPresentingUrl = action.url + if let url = action.url { + isPresentingSheet = .url(url) + } } func onHideAsset(_ assetId: AssetId) { @@ -198,7 +194,7 @@ extension WalletSceneViewModel { } public func onTransferComplete() { - isPresentingTransferData = nil + isPresentingSheet = nil } } diff --git a/Gem/Navigation/Wallet/WalletNavigationStack.swift b/Gem/Navigation/Wallet/WalletNavigationStack.swift index e64502933..500576546 100644 --- a/Gem/Navigation/Wallet/WalletNavigationStack.swift +++ b/Gem/Navigation/Wallet/WalletNavigationStack.swift @@ -104,8 +104,8 @@ struct WalletNavigationStack: View { PerpetualsNavigationView( wallet: model.wallet, perpetualService: AppResolver.main.services.perpetualService, - isPresentingSelectAssetType: $model.isPresentingSelectAssetType, - isPresentingTransferData: $model.isPresentingTransferData + isPresentingSelectAssetType: $model.isPresentingSheet.selectAssetType, + isPresentingTransferData: $model.isPresentingSheet.transferData ) } .navigationDestination(for: Scenes.Perpetual.self) { scene in @@ -113,53 +113,52 @@ struct WalletNavigationStack: View { perpetualData: scene.perpetualData, wallet: model.wallet, perpetualService: AppResolver.main.services.perpetualService, - isPresentingTransferData: $model.isPresentingTransferData, - isPresentingPerpetualRecipientData: $model.isPresentingPerpetualRecipientData + isPresentingTransferData: $model.isPresentingSheet.transferData, + isPresentingPerpetualRecipientData: $model.isPresentingSheet.perpetualRecipientData ) } - .sheet(item: $model.isPresentingSelectAssetType) { value in - SelectAssetSceneNavigationStack( - model: SelectAssetViewModel( - wallet: model.wallet, - selectType: value, - assetsService: walletsService.assetsService, - walletsService: walletsService, - priceAlertService: priceAlertService - ), - isPresentingSelectType: $model.isPresentingSelectAssetType - ) - } - .sheet(isPresented: $model.isPresentingWallets) { - WalletsNavigationStack(isPresentingWallets: $model.isPresentingWallets) - } - .sheet(item: $model.isPresentingInfoSheet) { - InfoSheetScene(model: InfoSheetViewModel(type: $0)) - } - .sheet(item: $model.isPresentingTransferData) { data in - ConfirmTransferNavigationStack( - wallet: model.wallet, - transferData: data, - onComplete: model.onTransferComplete - ) - } - .sheet(item: $model.isPresentingPerpetualRecipientData) { perpetualRecipientData in - AmountNavigationStack( - model: AmountSceneViewModel( - input: AmountInput( - type: .perpetual(recipient: perpetualRecipientData.recipientData, perpetualRecipientData.direction), - asset: perpetualRecipientData.asset + .sheet(item: $model.isPresentingSheet) { sheet in + switch sheet { + case let .selectAssetType(value): + SelectAssetSceneNavigationStack( + model: SelectAssetViewModel( + wallet: model.wallet, + selectType: value, + assetsService: walletsService.assetsService, + walletsService: walletsService, + priceAlertService: priceAlertService ), + isPresentingSelectType: $model.isPresentingSheet.selectAssetType + ) + case let .info(type): + InfoSheetScene(model: InfoSheetViewModel(type: type)) + case let .perpetualRecipientData(perpetualRecipientData): + AmountNavigationStack( + model: AmountSceneViewModel( + input: AmountInput( + type: .perpetual(recipient: perpetualRecipientData.recipientData, perpetualRecipientData.direction), + asset: perpetualRecipientData.asset + ), + wallet: model.wallet, + walletsService: walletsService, + stakeService: AppResolver.main.services.stakeService, + onTransferAction: { transferData in + model.isPresentingSheet = .transferData(transferData) + } + ) + ) + case let .transferData(transferData): + ConfirmTransferNavigationStack( wallet: model.wallet, - walletsService: walletsService, - stakeService: AppResolver.main.services.stakeService, - onTransferAction: { transferData in - model.isPresentingPerpetualRecipientData = nil - model.isPresentingTransferData = transferData - } + transferData: transferData, + onComplete: model.onTransferComplete ) - ) + case let .url(url): + SFSafariView(url: url) + case .wallets: + WalletsNavigationStack(isPresentingWallets: $model.isPresentingSheet.mappedToBool()) + } } - .safariSheet(url: $model.isPresentingUrl) } } } From 111c8df6d531af6e627a6ae1f5929fe0ef506644 Mon Sep 17 00:00:00 2001 From: gemdev111 Date: Mon, 28 Jul 2025 18:10:03 +0300 Subject: [PATCH 2/6] Refactor WalletSceneSheetType and navigation bindings Updated WalletSceneSheetType to use data.id for perpetualRecipientData and made the wallets binding public. Adjusted WalletNavigationStack to use the new wallets binding for presenting WalletsNavigationStack. --- Features/WalletTab/Sources/Types/WalletSceneSheetType.swift | 4 ++-- Gem/Navigation/Wallet/WalletNavigationStack.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift b/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift index 3cd288f53..599b1a674 100644 --- a/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift +++ b/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift @@ -20,7 +20,7 @@ public enum WalletSceneSheetType: Identifiable, Sendable { case let .info(type): "info-\(type.id)" case let .url(url): "url-\(url)" case let .transferData(data): "transfer-data-\(data.id)" - case let .perpetualRecipientData(data): "perpetual-recipient-data-\(data.asset.id.identifier)" + case let .perpetualRecipientData(data): "perpetual-recipient-data-\(data.id)" } } } @@ -70,7 +70,7 @@ extension Binding where Value == WalletSceneSheetType? { ) } - var wallets: Binding { + public var wallets: Binding { Binding( get: { if case .wallets = wrappedValue { return true } diff --git a/Gem/Navigation/Wallet/WalletNavigationStack.swift b/Gem/Navigation/Wallet/WalletNavigationStack.swift index 500576546..b97d748b6 100644 --- a/Gem/Navigation/Wallet/WalletNavigationStack.swift +++ b/Gem/Navigation/Wallet/WalletNavigationStack.swift @@ -156,7 +156,7 @@ struct WalletNavigationStack: View { case let .url(url): SFSafariView(url: url) case .wallets: - WalletsNavigationStack(isPresentingWallets: $model.isPresentingSheet.mappedToBool()) + WalletsNavigationStack(isPresentingWallets: $model.isPresentingSheet.wallets) } } } From 779465cfabaf445dc22756473de83f47020dbe3a Mon Sep 17 00:00:00 2001 From: gemdev111 Date: Thu, 9 Oct 2025 17:15:30 +0300 Subject: [PATCH 3/6] Update core --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 0bb6954cf..50209512b 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 0bb6954cfb1cd47488c13ffa485f8514a0ba3c13 +Subproject commit 50209512bc8665db13d925f1f86cf9fe177c19dc From 53320f17f5c093a7f0237bc54c0da699d4c15640 Mon Sep 17 00:00:00 2001 From: gemdev111 Date: Thu, 9 Oct 2025 17:25:49 +0300 Subject: [PATCH 4/6] Integrate set price alert into WalletSceneSheetType Added a new case for setPriceAlert in WalletSceneSheetType and updated related bindings. Refactored WalletSceneViewModel and WalletNavigationStack to use the unified sheet presentation for price alerts, removing the separate isPresentingSetPriceAlert property and sheet. This streamlines sheet management and improves code maintainability. --- .../Sources/Types/WalletSceneSheetType.swift | 16 ++++++++++++++++ .../ViewModels/WalletSceneViewModel.swift | 4 +--- .../Wallet/WalletNavigationStack.swift | 19 +++++++++---------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift b/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift index 599b1a674..a3a15c9e2 100644 --- a/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift +++ b/Features/WalletTab/Sources/Types/WalletSceneSheetType.swift @@ -12,6 +12,7 @@ public enum WalletSceneSheetType: Identifiable, Sendable { case url(URL) case transferData(TransferData) case perpetualRecipientData(PerpetualRecipientData) + case setPriceAlert(AssetId) public var id: String { switch self { @@ -21,6 +22,7 @@ public enum WalletSceneSheetType: Identifiable, Sendable { case let .url(url): "url-\(url)" case let .transferData(data): "transfer-data-\(data.id)" case let .perpetualRecipientData(data): "perpetual-recipient-data-\(data.id)" + case let .setPriceAlert(assetId): "set-price-alert-\(assetId.identifier)" } } } @@ -81,4 +83,18 @@ extension Binding where Value == WalletSceneSheetType? { } ) } + + public var setPriceAlert: Binding { + Binding( + get: { + if case .setPriceAlert(let assetId) = wrappedValue { + return assetId + } + return nil + }, + set: { newValue in + wrappedValue = newValue.map { .setPriceAlert($0) } + } + ) + } } diff --git a/Features/WalletTab/Sources/ViewModels/WalletSceneViewModel.swift b/Features/WalletTab/Sources/ViewModels/WalletSceneViewModel.swift index c279ec425..457505f66 100644 --- a/Features/WalletTab/Sources/ViewModels/WalletSceneViewModel.swift +++ b/Features/WalletTab/Sources/ViewModels/WalletSceneViewModel.swift @@ -38,7 +38,6 @@ public final class WalletSceneViewModel: Sendable { public var isPresentingSelectedAssetInput: Binding public var isPresentingSheet: WalletSceneSheetType? - public var isPresentingSetPriceAlert: AssetId? public var isPresentingToastMessage: ToastMessage? public var isPresentingSearch = false @@ -226,12 +225,11 @@ extension WalletSceneViewModel { } public func onSetPriceAlertComplete(message: String) { - isPresentingSetPriceAlert = nil + isPresentingSheet = nil isPresentingToastMessage = ToastMessage(title: message, image: SystemImage.bellFill) } } - // MARK: - Private extension WalletSceneViewModel { diff --git a/Gem/Navigation/Wallet/WalletNavigationStack.swift b/Gem/Navigation/Wallet/WalletNavigationStack.swift index 2e2c5c3bb..0ed9f8fd3 100644 --- a/Gem/Navigation/Wallet/WalletNavigationStack.swift +++ b/Gem/Navigation/Wallet/WalletNavigationStack.swift @@ -120,7 +120,7 @@ struct WalletNavigationStack: View { assetModel: AssetViewModel(asset: $0.asset), priceAlertService: priceAlertService, walletId: model.wallet.walletId, - isPresentingSetPriceAlert: $model.isPresentingSetPriceAlert + isPresentingSetPriceAlert: $model.isPresentingSheet.setPriceAlert ) ) } @@ -182,17 +182,16 @@ struct WalletNavigationStack: View { SFSafariView(url: url) case .wallets: WalletsNavigationStack(isPresentingWallets: $model.isPresentingSheet.wallets) + case let .setPriceAlert(assetId): + SetPriceAlertNavigationStack( + model: SetPriceAlertViewModel( + walletId: model.wallet.walletId, + assetId: assetId, + priceAlertService: priceAlertService + ) { model.onSetPriceAlertComplete(message: $0) } + ) } } - .sheet(item: $model.isPresentingSetPriceAlert) { assetId in - SetPriceAlertNavigationStack( - model: SetPriceAlertViewModel( - walletId: model.wallet.walletId, - assetId: assetId, - priceAlertService: priceAlertService - ) { model.onSetPriceAlertComplete(message: $0) } - ) - } .toast(message: $model.isPresentingToastMessage) } } From 21d48f1a25b148143cf6fdf56f91e7e1827bbf4f Mon Sep 17 00:00:00 2001 From: gemdev111 Date: Thu, 9 Oct 2025 17:29:07 +0300 Subject: [PATCH 5/6] Update core --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 50209512b..0bb6954cf 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 50209512bc8665db13d925f1f86cf9fe177c19dc +Subproject commit 0bb6954cfb1cd47488c13ffa485f8514a0ba3c13 From 3760a4a8b2fd40c7392f4bb40b2701b103ef99e3 Mon Sep 17 00:00:00 2001 From: gemdev111 Date: Thu, 9 Oct 2025 17:51:32 +0300 Subject: [PATCH 6/6] Update core --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 0bb6954cf..b44c72a42 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 0bb6954cfb1cd47488c13ffa485f8514a0ba3c13 +Subproject commit b44c72a427abaeab8a5fb5b3e151ebe185954528