diff --git a/Gem.xcodeproj/project.pbxproj b/Gem.xcodeproj/project.pbxproj index df4b8cd7..3b422214 100644 --- a/Gem.xcodeproj/project.pbxproj +++ b/Gem.xcodeproj/project.pbxproj @@ -522,6 +522,7 @@ D8C4A3722C8CE1EA006FABE8 /* TransferType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C4A3712C8CE1EA006FABE8 /* TransferType.swift */; }; D8C4A3742C8CE87C006FABE8 /* AmountNavigationFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C4A3732C8CE87C006FABE8 /* AmountNavigationFlow.swift */; }; D8C4A3762C8CF956006FABE8 /* StakeNavigationFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C4A3752C8CF956006FABE8 /* StakeNavigationFlow.swift */; }; + D8C4A3782C8D4D97006FABE8 /* ContactsNavigationStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C4A3772C8D4D97006FABE8 /* ContactsNavigationStack.swift */; }; D8C6E35E2B2243F500D0B513 /* StakeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8C6E35D2B2243F500D0B513 /* StakeViewModel.swift */; }; D8CD362B2C647D0300E18764 /* ChartSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8CD362A2C647D0300E18764 /* ChartSelection.swift */; }; D8CD362D2C6D504600E18764 /* LatencyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8CD362C2C6D504600E18764 /* LatencyViewModel.swift */; }; @@ -846,6 +847,7 @@ D8C4A3712C8CE1EA006FABE8 /* TransferType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferType.swift; sourceTree = ""; }; D8C4A3732C8CE87C006FABE8 /* AmountNavigationFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmountNavigationFlow.swift; sourceTree = ""; }; D8C4A3752C8CF956006FABE8 /* StakeNavigationFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakeNavigationFlow.swift; sourceTree = ""; }; + D8C4A3772C8D4D97006FABE8 /* ContactsNavigationStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsNavigationStack.swift; sourceTree = ""; }; D8C6E35D2B2243F500D0B513 /* StakeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakeViewModel.swift; sourceTree = ""; }; D8CD362A2C647D0300E18764 /* ChartSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartSelection.swift; sourceTree = ""; }; D8CD362C2C6D504600E18764 /* LatencyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatencyViewModel.swift; sourceTree = ""; }; @@ -1901,6 +1903,7 @@ children = ( D8C4A36B2C8CDB86006FABE8 /* TransferNavigationStack.swift */, D8C4A3732C8CE87C006FABE8 /* AmountNavigationFlow.swift */, + D8C4A3772C8D4D97006FABE8 /* ContactsNavigationStack.swift */, ); path = Navigation; sourceTree = ""; @@ -2428,6 +2431,7 @@ C3E99BCF2A787A8D005DF35F /* RateService.swift in Sources */, 835644FD2C501C2200C6B4DB /* SwapError.swift in Sources */, D848B5A32AE843B800814FB4 /* AssetTitleView.swift in Sources */, + D8C4A3782C8D4D97006FABE8 /* ContactsNavigationStack.swift in Sources */, D8C4A36C2C8CDB86006FABE8 /* TransferNavigationStack.swift in Sources */, C3549B4129C51BCE00B4BE01 /* BalanceViewModel.swift in Sources */, D890F79F2C7D216400C26819 /* WalletService.swift in Sources */, @@ -3307,7 +3311,7 @@ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.3.39; + MARKETING_VERSION = 1.3.42; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.gemwallet.ios.dev; "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = com.gemwallet.ios; @@ -3357,7 +3361,7 @@ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.3.39; + MARKETING_VERSION = 1.3.42; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.gemwallet.ios.dev; "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = com.gemwallet.ios; diff --git a/Gem/Transfer/Navigation/ContactsNavigationStack.swift b/Gem/Transfer/Navigation/ContactsNavigationStack.swift new file mode 100644 index 00000000..ebace9af --- /dev/null +++ b/Gem/Transfer/Navigation/ContactsNavigationStack.swift @@ -0,0 +1,30 @@ +// Copyright (c). Gem Wallet. All rights reserved. + +import Foundation +import SwiftUI +import Primitives + +struct ContactsNavigationStack: View { + + @Environment(\.keystore) private var keystore + @Environment(\.walletsService) private var walletsService + @Environment(\.stakeService) private var stakeService + @Environment(\.nodeService) private var nodeService + + let wallet: Wallet + let asset: Asset + + @State private var navigationPath = NavigationPath() + + var body: some View { + NavigationStack(path: $navigationPath) { + RecipientScene( + model: RecipientViewModel( + wallet: wallet, + keystore: keystore, + asset: asset + ) + ) + } + } +} diff --git a/Gem/Transfer/Scenes/AmountScene.swift b/Gem/Transfer/Scenes/AmountScene.swift index 271616af..6f6bfd33 100644 --- a/Gem/Transfer/Scenes/AmountScene.swift +++ b/Gem/Transfer/Scenes/AmountScene.swift @@ -14,6 +14,7 @@ struct AmountScene: View { @State private var isPresentingErrorMessage: String? @State private var isPresentingScanner: AmountScene.Field? + @State private var isPresentingContacts: Bool = false // focus enum Field: Int, Hashable, Identifiable { @@ -98,6 +99,9 @@ struct AmountScene: View { ListButton(image: Image(systemName: SystemImage.qrCode)) { isPresentingScanner = .address } +// ListButton(image: Image(systemName: SystemImage.book)) { +// isPresentingContacts = true +// } } } .focused($focusedField, equals: .address) @@ -195,6 +199,12 @@ struct AmountScene: View { onHandleScan($0, for: value) } } + .sheet(isPresented: $isPresentingContacts) { + ContactsNavigationStack( + wallet: model.wallet, + asset: model.asset + ) + } .navigationDestination(for: $transferData) { ConfirmTransferScene( model: ConfirmTransferViewModel( diff --git a/Gem/Transfer/Scenes/RecipientScene.swift b/Gem/Transfer/Scenes/RecipientScene.swift index fa7f882f..cfb53c75 100644 --- a/Gem/Transfer/Scenes/RecipientScene.swift +++ b/Gem/Transfer/Scenes/RecipientScene.swift @@ -7,46 +7,46 @@ import QRScanner import Blockchain import Primitives -//struct RecipientScene: View { -// -// let model: RecipientViewModel -// -// var body: some View { -// VStack { -// List { -// if !model.getRecipient(by: .wallets).isEmpty { -// Section { -// ForEach(model.getRecipient(by: .wallets)) { recipient in -// NavigationCustomLink(with: ListItemView(title: recipient.name)) { -// //address = recipient.address -// //focusedField = .none -// } -// } -// } header: { -// Text("My Wallets") -// } -// } -// if !model.getRecipient(by: .view).isEmpty { -// Section { -// ForEach(model.getRecipient(by: .view)) { recipient in -// NavigationCustomLink(with: ListItemView(title: recipient.name)) { -// //address = recipient.address -// //focusedField = .none -// } -// } -// } header: { -// Text("View Wallets") -// } -// } -// } -// .buttonStyle(.blue()) -// .padding(.bottom, Spacing.scene.bottom) -// .frame(maxWidth: Spacing.scene.button.maxWidth) -// } -// .background(Colors.grayBackground) -// .navigationTitle(model.tittle) -// } -//} +struct RecipientScene: View { + + let model: RecipientViewModel + + var body: some View { + VStack { + List { + if !model.getRecipient(by: .wallets).isEmpty { + Section { + ForEach(model.getRecipient(by: .wallets)) { recipient in + NavigationCustomLink(with: ListItemView(title: recipient.name)) { + //address = recipient.address + //focusedField = .none + } + } + } header: { + Text("My Wallets") + } + } + if !model.getRecipient(by: .view).isEmpty { + Section { + ForEach(model.getRecipient(by: .view)) { recipient in + NavigationCustomLink(with: ListItemView(title: recipient.name)) { + //address = recipient.address + //focusedField = .none + } + } + } header: { + Text("View Wallets") + } + } + } + .buttonStyle(.blue()) + .padding(.bottom, Spacing.scene.bottom) + .frame(maxWidth: Spacing.scene.button.maxWidth) + } + .background(Colors.grayBackground) + .navigationTitle(model.tittle) + } +} //struct TransferScene_Previews: PreviewProvider { // static var previews: some View { diff --git a/Gem/Transfer/ViewsModels/RecipientViewModel.swift b/Gem/Transfer/ViewsModels/RecipientViewModel.swift index 044768cc..74f22c92 100644 --- a/Gem/Transfer/ViewsModels/RecipientViewModel.swift +++ b/Gem/Transfer/ViewsModels/RecipientViewModel.swift @@ -4,95 +4,60 @@ import Keystore import Blockchain import GemstonePrimitives -//enum RecipientAddressType { -// case wallets -// case view -//} -// -//struct RecipientViewModel { -// let wallet: Wallet -// -// private let keystore: any Keystore -// private let walletsService: WalletsService -// private let assetModel: AssetViewModel -// -// init(wallet: Wallet, keystore: any Keystore, walletsService: WalletsService, assetModel: AssetViewModel) { -// self.wallet = wallet -// self.keystore = keystore -// self.walletsService = walletsService -// self.assetModel = assetModel -// } -// -// var asset: Asset { -// return assetModel.asset -// } -// -// var tittle: String { -// return Localized.Transfer.Recipient.title -// } -// -// var recipientField: String { -// return Localized.Transfer.Recipient.addressField -// } -// -// var memoField: String { -// return Localized.Transfer.memo -// } -// -// func isValidAddress(address: String) -> Bool { -// return asset.chain.isValidAddress(address) -// } -// -// var showMemo: Bool { -// return assetModel.supportMemo -// } -// -// func getRecipientData( -// asset: Asset, -// recipient: Recipient -// ) throws -> AmountRecipientData { -// guard isValidAddress(address: recipient.address) else { -// throw TransferError.invalidAddress(asset: asset) -// } -// -// return AmountRecipientData( -// type: .transfer, -// data: RecipientData( -// asset: asset, -// recipient: recipient -// ) -// ) -// } -// -// func getRecipient(by type: RecipientAddressType) -> [RecipientAddress] { -// switch type { -// case .wallets: -// return keystore.wallets -// .filter { ($0.type == .multicoin || $0.type == .single) && $0.id != wallet.id } -// .filter { $0.accounts.first(where: { $0.chain == asset.chain }) != nil } -// .map { -// return RecipientAddress( -// name: $0.name, -// address: $0.accounts.first(where: { $0.chain == asset.chain })!.address -// ) -// }.compactMap { $0 } -// case .view: -// return keystore.wallets.filter { $0.type == .view }.filter { $0.accounts[0].chain == asset.chain}.map { -// return RecipientAddress( -// name: $0.name, -// address: $0.accounts[0].address -// ) -// } -// } -// } -//} -// -//extension RecipientViewModel: Hashable { -// static func == (lhs: RecipientViewModel, rhs: RecipientViewModel) -> Bool { -// return lhs.wallet.id == rhs.wallet.id && lhs.asset == rhs.asset -// } -// -// func hash(into hasher: inout Hasher) { -// hasher.combine(wallet.id) -// } -//} +enum RecipientAddressType { + case wallets + case view +} + +struct RecipientViewModel { + let wallet: Wallet + + private let keystore: any Keystore + private let asset: Asset + + init( + wallet: Wallet, + keystore: any Keystore, + asset: Asset + ) { + self.wallet = wallet + self.keystore = keystore + self.asset = asset + } + + var tittle: String { + return Localized.Transfer.Recipient.title + } + + func getRecipient(by type: RecipientAddressType) -> [RecipientAddress] { + switch type { + case .wallets: + return keystore.wallets + .filter { ($0.type == .multicoin || $0.type == .single) && $0.id != wallet.id } + .filter { $0.accounts.first(where: { $0.chain == asset.chain }) != nil } + .map { + return RecipientAddress( + name: $0.name, + address: $0.accounts.first(where: { $0.chain == asset.chain })!.address + ) + }.compactMap { $0 } + case .view: + return keystore.wallets.filter { $0.type == .view }.filter { $0.accounts[0].chain == asset.chain}.map { + return RecipientAddress( + name: $0.name, + address: $0.accounts[0].address + ) + } + } + } +} + +extension RecipientViewModel: Hashable { + static func == (lhs: RecipientViewModel, rhs: RecipientViewModel) -> Bool { + return lhs.wallet.id == rhs.wallet.id && lhs.asset == rhs.asset + } + + func hash(into hasher: inout Hasher) { + hasher.combine(wallet.id) + } +} diff --git a/Packages/Style/Sources/SystemImage.swift b/Packages/Style/Sources/SystemImage.swift index be1bfd3c..dd3577e2 100644 --- a/Packages/Style/Sources/SystemImage.swift +++ b/Packages/Style/Sources/SystemImage.swift @@ -38,6 +38,7 @@ public struct SystemImage { public static let unpin = "pin.slash" public static let filter = "line.horizontal.3.decrease.circle" public static let filterFill = "line.horizontal.3.decrease.circle.fill" + public static let book = "book" } // MARK: - Previews @@ -78,6 +79,7 @@ public struct SystemImage { (SystemImage.unpin, "Unpin"), (SystemImage.filter, "Filter"), (SystemImage.filterFill, "Filter Fill"), + (SystemImage.book, "book"), ] return List {