diff --git a/Adamant/Modules/ChatsList/ComplexTransferViewController.swift b/Adamant/Modules/ChatsList/ComplexTransferViewController.swift index f60a8915f..ad8dae172 100644 --- a/Adamant/Modules/ChatsList/ComplexTransferViewController.swift +++ b/Adamant/Modules/ChatsList/ComplexTransferViewController.swift @@ -193,7 +193,7 @@ extension ComplexTransferViewController: PagingViewControllerDataSource { "ApiService.InternalError.NoNodesAvailable", comment: "Wallet Services: Shared error, user has not yet initiated a specific wallet." ), - String(services[index].core.tokenName) + String(services[index].core.tokenSymbol) ), animated: true ) diff --git a/Adamant/Modules/ChatsList/NewChatViewController.swift b/Adamant/Modules/ChatsList/NewChatViewController.swift index a74eef3c7..576b4297a 100644 --- a/Adamant/Modules/ChatsList/NewChatViewController.swift +++ b/Adamant/Modules/ChatsList/NewChatViewController.swift @@ -313,7 +313,7 @@ final class NewChatViewController: FormViewController { switch error { case .dummy, .notFound, .notInitiated: self.dialogService.dismissProgress() - + dialogService.presentDummyChatAlert( for: address, from: nil, @@ -456,16 +456,14 @@ extension NewChatViewController { extension NewChatViewController: QRCodeReaderViewControllerDelegate { nonisolated func reader(_ reader: QRCodeReaderViewController, didScanResult result: QRCodeReaderResult) { MainActor.assumeIsolatedSafe { - if let admAddress = result.value.getAdamantAddress() { - startNewChat(with: admAddress.address, name: admAddress.name, message: admAddress.message) - dismiss(animated: true, completion: nil) - } else if let admAddress = result.value.getLegacyAdamantAddress() { - startNewChat(with: admAddress.address, name: admAddress.name, message: admAddress.message) - dismiss(animated: true, completion: nil) - } else { - dialogService.showWarning(withMessage: String.adamant.newChat.wrongQrError) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - reader.startScanning() + Task { @MainActor in + await dismissAsync(reader) + if let a = result.value.getAdamantAddress() { + startNewChat(with: a.address, name: a.name, message: a.message) + } else if let a = result.value.getLegacyAdamantAddress() { + startNewChat(with: a.address, name: a.name, message: a.message) + } else { + dialogService.showWarning(withMessage: String.adamant.newChat.wrongQrError) } } } @@ -480,29 +478,39 @@ extension NewChatViewController: QRCodeReaderViewControllerDelegate { // MARK: - UIImagePickerControllerDelegate extension NewChatViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate { - func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { - dismiss(animated: true, completion: nil) - - guard let image = info[.originalImage] as? UIImage, let cgImage = image.cgImage else { - return + /// Waits for UIKit to finish dismissing `vc` (animation + completion). + /// Bridges the dismiss completion callback into async/await so callers can safely present next UI after it's fully gone. + @MainActor + private func dismissAsync(_ vc: UIViewController, animated: Bool = true) async { + await withCheckedContinuation { (cont: CheckedContinuation) in + vc.dismiss(animated: animated) { + // Resume when UIKit reports the dismissal is complete. + cont.resume(returning: ()) + } } + } - let codes = EFQRCode.recognize(cgImage) - - if codes.count > 0 { - for aCode in codes { - if let admAddress = aCode.getAdamantAddress() { - startNewChat(with: admAddress.address, name: admAddress.name, message: admAddress.message) - return - } else if let admAddress = aCode.getLegacyAdamantAddress() { - startNewChat(with: admAddress.address, name: admAddress.name, message: nil) - return + + @MainActor + func imagePickerController( + _ picker: UIImagePickerController, + didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any] + ) { + Task { @MainActor in + await dismissAsync(picker) + + if let image = info[.originalImage] as? UIImage, let cg = image.cgImage { + let codes = EFQRCode.recognize(cg) + if let c = codes.first, let adm = c.getAdamantAddress() { + startNewChat(with: adm.address, name: adm.name, message: adm.message) + } else if let c = codes.first, let adm = c.getLegacyAdamantAddress() { + startNewChat(with: adm.address, name: adm.name, message: nil) + } else { + dialogService.showWarning(withMessage: String.adamant.newChat.wrongQrError) } + } else { + dialogService.showWarning(withMessage: String.adamant.login.noQrError) } - - dialogService.showWarning(withMessage: String.adamant.newChat.wrongQrError) - } else { - dialogService.showWarning(withMessage: String.adamant.login.noQrError) } } } diff --git a/Adamant/Modules/Wallets/Bitcoin/BtcWalletService.swift b/Adamant/Modules/Wallets/Bitcoin/BtcWalletService.swift index cf419cf94..2d0653cb9 100644 --- a/Adamant/Modules/Wallets/Bitcoin/BtcWalletService.swift +++ b/Adamant/Modules/Wallets/Bitcoin/BtcWalletService.swift @@ -409,7 +409,7 @@ final class BtcWalletService: WalletCoreProtocol, WalletStaticCoreProtocol, @unc let result = try await apiService.get(key: BtcWalletService.kvsAddress, sender: address).get() guard let result = result else { - throw WalletServiceError.walletNotInitiated(tokenName: self.tokenName) + throw WalletServiceError.walletNotInitiated(tokenName: self.tokenSymbol) } cachedWalletAddress[address] = result @@ -550,7 +550,7 @@ extension BtcWalletService: SwinjectDependentService { extension BtcWalletService { func getBalance() async throws -> Decimal { guard let address = btcWallet?.address else { - throw WalletServiceError.walletNotInitiated(tokenName: self.tokenName) + throw WalletServiceError.walletNotInitiated(tokenName: self.tokenSymbol) } return try await getBalance(address: address) diff --git a/Adamant/Modules/Wallets/Dash/DashWalletService.swift b/Adamant/Modules/Wallets/Dash/DashWalletService.swift index b926a8afe..fb3d39e0d 100644 --- a/Adamant/Modules/Wallets/Dash/DashWalletService.swift +++ b/Adamant/Modules/Wallets/Dash/DashWalletService.swift @@ -411,7 +411,7 @@ extension DashWalletService: SwinjectDependentService { extension DashWalletService { func getBalance() async throws -> Decimal { guard let address = dashWallet?.address else { - throw WalletServiceError.walletNotInitiated(tokenName: self.tokenName) + throw WalletServiceError.walletNotInitiated(tokenName: self.tokenSymbol) } return try await getBalance(address: address) @@ -463,7 +463,7 @@ extension DashWalletService { let result = try await apiService.get(key: DashWalletService.kvsAddress, sender: address).get() guard let result = result else { - throw WalletServiceError.walletNotInitiated(tokenName: self.tokenName) + throw WalletServiceError.walletNotInitiated(tokenName: self.tokenSymbol) } cachedWalletAddress[address] = result diff --git a/Adamant/Modules/Wallets/Doge/DogeWalletService.swift b/Adamant/Modules/Wallets/Doge/DogeWalletService.swift index 44bbc1359..ec32bab31 100644 --- a/Adamant/Modules/Wallets/Doge/DogeWalletService.swift +++ b/Adamant/Modules/Wallets/Doge/DogeWalletService.swift @@ -428,7 +428,7 @@ extension DogeWalletService: SwinjectDependentService { extension DogeWalletService { func getBalance() async throws -> Decimal { guard let address = dogeWallet?.address else { - throw WalletServiceError.walletNotInitiated(tokenName: self.tokenName) + throw WalletServiceError.walletNotInitiated(tokenName: self.tokenSymbol) } return try await getBalance(address: address) @@ -460,7 +460,7 @@ extension DogeWalletService { let result = try await apiService.get(key: DogeWalletService.kvsAddress, sender: address).get() guard let result = result else { - throw WalletServiceError.walletNotInitiated(tokenName: self.tokenName) + throw WalletServiceError.walletNotInitiated(tokenName: self.tokenSymbol) } cachedWalletAddress[address] = result diff --git a/Adamant/Modules/Wallets/ERC20/ERC20WalletService.swift b/Adamant/Modules/Wallets/ERC20/ERC20WalletService.swift index dd2e09bf9..c5793ed9a 100644 --- a/Adamant/Modules/Wallets/ERC20/ERC20WalletService.swift +++ b/Adamant/Modules/Wallets/ERC20/ERC20WalletService.swift @@ -533,7 +533,7 @@ extension ERC20WalletService { let result = try await apiService.get(key: EthWalletService.kvsAddress, sender: address).get() guard let result = result else { - throw WalletServiceError.walletNotInitiated(tokenName: self.tokenName) + throw WalletServiceError.walletNotInitiated(tokenName: self.tokenSymbol) } cachedWalletAddress[address] = result diff --git a/Adamant/Modules/Wallets/Ethereum/EthWalletService.swift b/Adamant/Modules/Wallets/Ethereum/EthWalletService.swift index a99cba7c8..785012fad 100644 --- a/Adamant/Modules/Wallets/Ethereum/EthWalletService.swift +++ b/Adamant/Modules/Wallets/Ethereum/EthWalletService.swift @@ -577,7 +577,7 @@ extension EthWalletService { let result = try await apiService.get(key: EthWalletService.kvsAddress, sender: address).get() guard let result = result else { - throw WalletServiceError.walletNotInitiated(tokenName: self.tokenName) + throw WalletServiceError.walletNotInitiated(tokenName: self.tokenSymbol) } cachedWalletAddress[address] = result diff --git a/Adamant/Services/DataProviders/AdamantAccountsProvider.swift b/Adamant/Services/DataProviders/AdamantAccountsProvider.swift index 0536b5dda..3d9ce73fe 100644 --- a/Adamant/Services/DataProviders/AdamantAccountsProvider.swift +++ b/Adamant/Services/DataProviders/AdamantAccountsProvider.swift @@ -235,12 +235,15 @@ extension AdamantAccountsProvider { // Check if there is an account, that we are looking for let dummy: DummyAccount? switch getAccount(byPredicate: NSPredicate(format: "address == %@", address)) { - case .core(let account): - return account - case .dummy(let account): - dummy = account - case .notFound: - dummy = nil + case .core(let account): + dummy = nil + if !account.isDummy { + return account + } + case .dummy(let account): + dummy = account + case .notFound: + dummy = nil } switch validation { @@ -385,8 +388,34 @@ extension AdamantAccountsProvider { in context: NSManagedObjectContext ) -> CoreDataAccount { let result = getAccount(byPredicate: NSPredicate(format: "address == %@", account.address)) - if case .core(let account) = result { - return account + if case .core(let existingAccount) = result { + // If account does not contain publicKey we mark it as dummy, but every new account has a small time being without publick key. + // So this checking needs to update previously created dummy account if it is not dummy anymore + + // If existing account is dummy, update it with real data + if existingAccount.isDummy, !account.isDummy { + existingAccount.publicKey = account.publicKey + existingAccount.isDummy = account.isDummy + + // If we have dummy account data, transfer it + if let dummy = dummy { + existingAccount.name = dummy.name + + if let transfers = dummy.transfers { + dummy.removeFromTransfers(transfers) + existingAccount.addToTransfers(transfers) + + if let chatroom = existingAccount.chatroom { + chatroom.addToTransactions(transfers) + chatroom.updateLastTransaction() + } + } + context.delete(dummy) + } + + try? context.save() + } + return existingAccount } let coreAccount = createCoreDataAccount(from: account, context: context) diff --git a/Adamant/SharedViews/FullscreenAlertView.swift b/Adamant/SharedViews/FullscreenAlertView.swift index 5dfcfbf9c..d31f10703 100644 --- a/Adamant/SharedViews/FullscreenAlertView.swift +++ b/Adamant/SharedViews/FullscreenAlertView.swift @@ -130,6 +130,7 @@ extension FullscreenAlertView { $0.center.equalToSuperview() $0.top.leading.greaterThanOrEqualToSuperview().inset(15) $0.bottom.trailing.lessThanOrEqualToSuperview().inset(15) + $0.width.equalTo(300) } containerView.addSubview(verticalStack) diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings index 4376a8e80..b2abcce21 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/de.lproj/Localizable.strings @@ -290,7 +290,7 @@ "ApiService.InternalError.ParsingFailed" = "Parsing fehlgeschlagen. Bericht senden"; /* Serious internal error: No nodes available */ -"ApiService.InternalError.NoNodesAvailable" = "Die Wallet-Adresse des Benutzers für %@ konnte nicht abgerufen werden\nBitte überprüfen Sie Ihre Verbindung."; +"ApiService.InternalError.NoNodesAvailable" = "Die Wallet-Adresse des Benutzers für %@ konnte nicht abgerufen werden\n\nBitte überprüfen Sie Ihre Verbindung."; "ApiService.InternalError.NoEndpointsAvailable" = "Keine aktiven %@ Knoten. Überprüfen Sie die Knotenliste."; /* Serious internal error: No ADM nodes available */ diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings index 8dea0c7a7..1512e51a0 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/en.lproj/Localizable.strings @@ -287,7 +287,7 @@ "ApiService.InternalError.ParsingFailed" = "Parsing failed. Report a bug"; /* Serious internal error: No nodes available */ -"ApiService.InternalError.NoNodesAvailable" = "Failed to retrieve the user’s %@ wallet address\nPlease check your connection"; +"ApiService.InternalError.NoNodesAvailable" = "Failed to retrieve the user’s %@ wallet address\n\nPlease check your connection"; "ApiService.InternalError.NoEndpointsAvailable" = "No active %@ nodes. Review the node list"; /* Serious internal error: No ADM nodes available */ diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings index cad78173b..40954faa6 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/ru.lproj/Localizable.strings @@ -287,7 +287,7 @@ "ApiService.InternalError.ParsingFailed" = "Не удалось разобрать ответ узла блокчена. Сообщите разработчикам"; /* Serious internal error: No nodes available */ -"ApiService.InternalError.NoNodesAvailable" = "Не удалось получить адрес %@-кошелька пользователя\nПроверьте подключение"; +"ApiService.InternalError.NoNodesAvailable" = "Не удалось получить адрес %@-кошелька пользователя\n\nПроверьте подключение"; "ApiService.InternalError.NoEndpointsAvailable" = "Нет доступных %@ нод. Просмотрите список узлов"; /* Serious internal error: No ADM nodes available */ diff --git a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings index 0a408ff7f..b6b10ff8d 100644 --- a/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings +++ b/CommonKit/Sources/CommonKit/Assets/Localization/zh.lproj/Localizable.strings @@ -287,7 +287,7 @@ "ApiService.InternalError.PassingFailed" = "分析失败。报告错误"; /* Serious internal error: No nodes available */ -"ApiService.InternalError.NoNodesAvailable" = "无法获取用户的%@钱包地址。\n请检查您的网络连接。"; +"ApiService.InternalError.NoNodesAvailable" = "无法获取用户的%@钱包地址。\n\n请检查您的网络连接。"; "ApiService.InternalError.NoEndpointsAvailable" = "没有活动的%@节点。查看节点列表"; /* Serious internal error: No ADM nodes available */