From 16dfc08f4562e0d18ad2c113c01fba69114c7846 Mon Sep 17 00:00:00 2001 From: Skibin Alexander <5384724+skibinalexander@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:06:06 +0300 Subject: [PATCH 1/8] IOS-8994 Fix compound sending (#4515) --- BlockchainSdk/Common/Blockchain.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/BlockchainSdk/Common/Blockchain.swift b/BlockchainSdk/Common/Blockchain.swift index 2232b02a47..d35cf9b8db 100644 --- a/BlockchainSdk/Common/Blockchain.swift +++ b/BlockchainSdk/Common/Blockchain.swift @@ -228,7 +228,8 @@ public indirect enum Blockchain: Equatable, Hashable { .dash, .kaspa, .ravencoin, - .ducatus: + .ducatus, + .fact0rn: return true default: return false @@ -250,7 +251,8 @@ public indirect enum Blockchain: Equatable, Hashable { .dash, .kaspa, .ravencoin, - .ducatus: + .ducatus, + .fact0rn: return true default: return false From 2f49c620d24a0a2a7f3c306704814a0baca46880 Mon Sep 17 00:00:00 2001 From: Sergei Balashov Date: Tue, 21 Jan 2025 14:18:55 +0000 Subject: [PATCH 2/8] IOS-8937 Update EstimationFeeAddress for LTC (#4513) --- .../Common/Factories/EstimationFeeAddressFactory.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlockchainSdk/Common/Factories/EstimationFeeAddressFactory.swift b/BlockchainSdk/Common/Factories/EstimationFeeAddressFactory.swift index 8714da83ec..49f2d1e6a7 100644 --- a/BlockchainSdk/Common/Factories/EstimationFeeAddressFactory.swift +++ b/BlockchainSdk/Common/Factories/EstimationFeeAddressFactory.swift @@ -42,7 +42,7 @@ struct EstimationFeeAddressFactory { case .bitcoin: return "bc1qkrc5kmpq546wr2xk0errg58yw9jjq7thvhdk5k" case .litecoin: - return "MSqjXH6toL4kHqsRo3mWaWMkhmiH9GQxLR" + return "LeAXZ4WKNy8zeybFkD6scFpBSmCPmENUEW" case .bitcoinCash: return "bitcoincash:qrn96yyxa93t6sqmehvls6746qafkcsuku6zmd9460" case .dogecoin: From 7581ddba8460a387ac413b34ca7e0e6c6d7636ee Mon Sep 17 00:00:00 2001 From: Aleksei Lobankov Date: Tue, 21 Jan 2025 17:51:01 +0300 Subject: [PATCH 3/8] IOS-9000 Blockchain.coinDisplayName fixed for odysseyChain. (#4518) --- BlockchainSdk/Common/Blockchain.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BlockchainSdk/Common/Blockchain.swift b/BlockchainSdk/Common/Blockchain.swift index d35cf9b8db..93768d3d28 100644 --- a/BlockchainSdk/Common/Blockchain.swift +++ b/BlockchainSdk/Common/Blockchain.swift @@ -607,6 +607,8 @@ public indirect enum Blockchain: Equatable, Hashable { "Toncoin" case .fantom: "Fantom" + case .odysseyChain: + "Dione" default: displayName } From 97f62d5311222a9a1afe09843a7591c44a61d34b Mon Sep 17 00:00:00 2001 From: Aleksei Lobankov Date: Tue, 21 Jan 2025 18:20:55 +0300 Subject: [PATCH 4/8] IOS-8999 BitrockExternalLinkProvider baseExplorerUrl fixed for mainnet (#4519) --- .../Ethereum/OtherChains/BitrockExternalLinkProvider.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlockchainSdk/Blockchains/Ethereum/OtherChains/BitrockExternalLinkProvider.swift b/BlockchainSdk/Blockchains/Ethereum/OtherChains/BitrockExternalLinkProvider.swift index 02f4a21016..87b78cbabb 100644 --- a/BlockchainSdk/Blockchains/Ethereum/OtherChains/BitrockExternalLinkProvider.swift +++ b/BlockchainSdk/Blockchains/Ethereum/OtherChains/BitrockExternalLinkProvider.swift @@ -14,7 +14,7 @@ struct BitrockExternalLinkProvider: ExternalLinkProvider { init(isTestnet: Bool) { baseExplorerUrl = isTestnet ? "https://testnetscan.bit-rock.io" - : "https://scan.bit-rock.io" + : "https://explorer.bit-rock.io" } func url(address: String, contractAddress: String?) -> URL? { From 1a15123bd63f7e6cbfb0962af43d26ba3c4d3d6a Mon Sep 17 00:00:00 2001 From: Andrey Fedorov Date: Wed, 22 Jan 2025 15:39:05 +0100 Subject: [PATCH 5/8] IOS-8943: Protect inputs from screen recording (#4504) Signed-off-by: Andrey Fedorov --- Modules/Package.swift | 9 +- Modules/TangemUI/Components/.gitkeep | 0 .../GeometryInfoReaderViewModifier.swift | 110 +++++----- .../ScreenCaptureProtectionViewModifier.swift | 188 ++++++++++++++++++ .../Extensions/UIApplication+.swift | 2 +- .../Extensions/UIDevice+.swift | 2 +- ...xtInputSecurityHardeningConfigurator.swift | 2 +- .../Extensions/View+ReadContentOffset.swift | 1 + Tangem/Common/UI/CircleCheckmarkIcon.swift | 1 + .../ExpressCurrencyView.swift | 1 + ...resentationConfigurationViewModifier.swift | 0 .../Common/UI/Navigation/NavigationBar.swift | 1 + .../SendDecimalNumberTextField.swift | 1 + .../UI/TextInputs/CustomTextField.swift | 2 +- Tangem/Modules/ExpressView/ExpressView.swift | 1 + .../Empty/EmptyMainFooterView.swift | 2 +- .../MainBottomSheetFooterView.swift | 2 +- .../Main/MainHeaderView/MainHeaderView.swift | 1 + .../MainBottomSheetHintView.swift | 1 + .../GenerateAddressesView.swift | 2 +- .../MarketsTokenDetailsView.swift | 1 + ...MarketsTokenDetailsExchangesListView.swift | 1 + .../MarketsPortfolioTokenItemView.swift | 1 + .../Markets/TokenList/MarketsView.swift | 1 + ...MarketsTokensNetworkSelectorItemView.swift | 1 + .../Note/SingleCardOnboardingView.swift | 1 + .../Twins/TwinsOnboardingView.swift | 1 + .../Views/Animators/CardStackAnimator.swift | 1 + .../Views/Animators/FanStackCalculator.swift | 1 + .../OnboardingProgressCheckmarksView.swift | 1 + .../OnboardingSeedPhraseGenerateView.swift | 15 +- .../OnboardingSeedPhraseImportView.swift | 3 + ...boardingSeedPhraseUserValidationView.swift | 49 +++-- .../Views/SeedPhrase/SeedPhraseTextView.swift | 2 +- .../Wallet/WalletOnboardingView.swift | 1 + .../ListFooter/OrganizeTokensListFooter.swift | 1 + .../OrganizeTokens/OrganizeTokensView.swift | 1 + .../ResetToFactory/ResetToFactoryView.swift | 2 +- .../SendAmountCompactView.swift | 1 + .../AddressView/AddressTextView.swift | 1 + .../SendDestinationCompactView.swift | 1 + .../SendFeeCompactView.swift | 1 + .../StakingValidatorsCompactView.swift | 1 + .../StakingDetails/StakingDetailsView.swift | 1 + Tangem/RootViewControllerFactory.swift | 2 +- .../BottomSheet/BottomSheetContainer.swift | 3 +- .../CardsInfoPagerView.swift | 1 + .../UIComponents/Common/CustomSearchBar.swift | 2 +- .../TokenDescriptionBottomSheetView.swift | 2 +- .../View+AdaptiveSizeSheetModifier.swift | 1 + .../ManageTokensItemNetworkSelectorView.swift | 1 + ...verlayContentContainerViewController.swift | 2 +- .../ReceiveBottomSheetView.swift | 1 + .../SegmentedPickerView.swift | 1 + .../TokenItemView/TokenItemView.swift | 1 + TangemApp.xcodeproj/project.pbxproj | 8 +- 56 files changed, 346 insertions(+), 98 deletions(-) create mode 100644 Modules/TangemUI/Components/.gitkeep rename Tangem/Common/Extensions/View+ReadGeometry.swift => Modules/TangemUI/Modifiers/GeometryInfoReaderViewModifier.swift (86%) create mode 100644 Modules/TangemUI/Modifiers/ScreenCaptureProtectionViewModifier.swift rename Modules/{TangemUIKitUtils => TangemUIUtils}/Extensions/UIApplication+.swift (94%) rename Modules/{TangemUIKitUtils => TangemUIUtils}/Extensions/UIDevice+.swift (94%) rename Modules/{TangemUIKitUtils/Extensions => TangemUIUtils/Helpers}/UITextInputSecurityHardeningConfigurator.swift (99%) rename Tangem/Common/{Extensions/UIKit => UI/Modifiers}/PresentationConfigurationViewModifier.swift (100%) diff --git a/Modules/Package.swift b/Modules/Package.swift index da6a3e6c2e..a727847faf 100644 --- a/Modules/Package.swift +++ b/Modules/Package.swift @@ -49,7 +49,14 @@ var serviceModules: [PackageDescription.Target] { ] ), .tangemTarget( - name: "TangemUIKitUtils", + name: "TangemUIUtils", + swiftSettings: [ + // TODO: Andrey Fedorov - Remove after migration to Swift 6 structured concurrency (IOS-8369) + .swiftLanguageMode(.v5), + ] + ), + .tangemTarget( + name: "TangemUI", swiftSettings: [ // TODO: Andrey Fedorov - Remove after migration to Swift 6 structured concurrency (IOS-8369) .swiftLanguageMode(.v5), diff --git a/Modules/TangemUI/Components/.gitkeep b/Modules/TangemUI/Components/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tangem/Common/Extensions/View+ReadGeometry.swift b/Modules/TangemUI/Modifiers/GeometryInfoReaderViewModifier.swift similarity index 86% rename from Tangem/Common/Extensions/View+ReadGeometry.swift rename to Modules/TangemUI/Modifiers/GeometryInfoReaderViewModifier.swift index 11aa2a45a5..f27514d7c1 100644 --- a/Tangem/Common/Extensions/View+ReadGeometry.swift +++ b/Modules/TangemUI/Modifiers/GeometryInfoReaderViewModifier.swift @@ -1,6 +1,6 @@ // -// View+ReadGeometry.swift -// Tangem +// GeometryInfoReaderViewModifier.swift +// TangemUI // // Created by Andrey Fedorov on 14.06.2023. // Copyright © 2023 Tangem AG. All rights reserved. @@ -8,60 +8,9 @@ import SwiftUI -struct GeometryInfo: Equatable { - static var zero: Self { - return GeometryInfo( - coordinateSpace: .local, - frame: .zero, - size: .zero, - safeAreaInsets: .init() - ) - } - - let coordinateSpace: CoordinateSpace - let frame: CGRect - let size: CGSize - let safeAreaInsets: EdgeInsets - - fileprivate init( - coordinateSpace: CoordinateSpace, - frame: CGRect, - size: CGSize, - safeAreaInsets: EdgeInsets - ) { - self.coordinateSpace = coordinateSpace - self.frame = frame - self.size = size - self.safeAreaInsets = safeAreaInsets - } -} - -extension GeometryInfo { - struct ThrottleInterval: ExpressibleByFloatLiteral { - // No throttling at all. - static let zero = ThrottleInterval(0.0) - /// Aggressive throttling, use for non-precision tasks. - static let aggressive = ThrottleInterval(1.0 / 30.0) - /// Standard 60 FPS (single frame duration: ~16msec). - static let standard = ThrottleInterval(1.0 / 60.0) - /// 120 FPS on ProMotion capable devices (single frame duration: ~8msec). - static let proMotion = ThrottleInterval(1.0 / 120.0) - - fileprivate let value: CFTimeInterval - - init(_ value: CFTimeInterval) { - self.value = value - } - - init(floatLiteral value: CFTimeInterval) { - self.value = value - } - } -} - // MARK: - Convenience extensions -extension View { +public extension View { /// Closure-based helper. Use optional `keyPath` parameter if you aren't interested /// in the whole `GeometryInfo` but rather a single property of it. func readGeometry( @@ -111,6 +60,59 @@ extension View { } } +// MARK: - Auxiliary types + +public struct GeometryInfo: Equatable { + public static var zero: Self { + return GeometryInfo( + coordinateSpace: .local, + frame: .zero, + size: .zero, + safeAreaInsets: .init() + ) + } + + public let coordinateSpace: CoordinateSpace + public let frame: CGRect + public let size: CGSize + public let safeAreaInsets: EdgeInsets + + fileprivate init( + coordinateSpace: CoordinateSpace, + frame: CGRect, + size: CGSize, + safeAreaInsets: EdgeInsets + ) { + self.coordinateSpace = coordinateSpace + self.frame = frame + self.size = size + self.safeAreaInsets = safeAreaInsets + } +} + +public extension GeometryInfo { + struct ThrottleInterval: ExpressibleByFloatLiteral { + // No throttling at all. + public static let zero = ThrottleInterval(0.0) + /// Aggressive throttling, use for non-precision tasks. + public static let aggressive = ThrottleInterval(1.0 / 30.0) + /// Standard 60 FPS (single frame duration: ~16msec). + public static let standard = ThrottleInterval(1.0 / 60.0) + /// 120 FPS on ProMotion capable devices (single frame duration: ~8msec). + public static let proMotion = ThrottleInterval(1.0 / 120.0) + + fileprivate let value: CFTimeInterval + + public init(_ value: CFTimeInterval) { + self.value = value + } + + public init(floatLiteral value: CFTimeInterval) { + self.value = value + } + } +} + // MARK: - Private implementation private struct GeometryInfoReaderViewModifier: ViewModifier { diff --git a/Modules/TangemUI/Modifiers/ScreenCaptureProtectionViewModifier.swift b/Modules/TangemUI/Modifiers/ScreenCaptureProtectionViewModifier.swift new file mode 100644 index 0000000000..5587315f99 --- /dev/null +++ b/Modules/TangemUI/Modifiers/ScreenCaptureProtectionViewModifier.swift @@ -0,0 +1,188 @@ +// +// ScreenCaptureProtectionViewModifier.swift +// TangemUI +// +// Created by Andrey Fedorov on 17.01.2025. +// Copyright © 2025 Tangem AG. All rights reserved. +// + +import Foundation +import SwiftUI +import UIKit + +// MARK: - Convenience extensions + +public extension View { + /// Protects the given view from both screenshots and built-in screen recording. + @ViewBuilder + func screenCaptureProtection() -> some View { + if #available(iOS 16.0, *) { + modifier(ScreenCaptureProtectionIOS16AndAboveViewModifier()) + } else { + modifier(ScreenCaptureProtectionIOS15AndBelowViewModifier()) + } + } +} + +// MARK: - Private implementation iOS 15 + +@available(iOS, deprecated: 16.0, message: "Not used on iOS 16+, can be safely removed") +private struct ScreenCaptureProtectionIOS15AndBelowViewModifier: ViewModifier { + @State private var contentSizeChange: CGSize? + + func body(content: Content) -> some View { + ScreenCaptureProtectionContainerView( + content: { content }, + onContentSizeChange: { contentSizeChange = $0 } + ) + .frame(width: contentSizeChange?.width, height: contentSizeChange?.height) + } +} + +// MARK: - Private implementation iOS 16+ + +@available(iOS 16.0, *) +private struct ScreenCaptureProtectionIOS16AndAboveViewModifier: ViewModifier { + func body(content: Content) -> some View { + ScreenCaptureProtectionContainerView { content } + } +} + +@available(iOS 16.0, *) +private final class PreferredContentSizeForwardingUIHostingController: UIHostingController where T: View { + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + let contentSize = view.bounds.size + if contentSize != preferredContentSize { + preferredContentSize = view.bounds.size + } + } +} + +// MARK: - Private implementation common + +private struct ScreenCaptureProtectionContainerView: UIViewControllerRepresentable where Content: View { + typealias UIViewControllerType = UIViewController + + @available(iOS, deprecated: 16.0, message: "Not used on iOS 16+, can be safely removed") + typealias OnContentSizeChange = (_ size: CGSize) -> Void + + @available(iOS, deprecated: 16.0, message: "Not used on iOS 16+, can be safely removed") + private let onContentSizeChange: OnContentSizeChange? + + private let content: () -> Content + + @available(iOS, deprecated: 16.0, message: "Use 'init(content:)' instead. Not used on iOS 16+, can be safely removed") + init( + content: @escaping () -> Content, + onContentSizeChange: @escaping OnContentSizeChange + ) { + self.content = content + self.onContentSizeChange = onContentSizeChange + } + + @available(iOS 16.0, *) + init( + content: @escaping () -> Content + ) { + self.content = content + onContentSizeChange = nil + } + + func makeUIViewController(context: Context) -> UIViewControllerType { + let containerViewController = ScreenCaptureProtectionContainerViewController() + let contentViewController: UIViewControllerType + + if #available(iOS 16.0, *) { + let hostingViewController = PreferredContentSizeForwardingUIHostingController(rootView: content()) + hostingViewController.sizingOptions = .preferredContentSize + contentViewController = hostingViewController + } else { + let rootView = content() + .readGeometry(\.size) { size in + onContentSizeChange?(size) + } + contentViewController = UIHostingController(rootView: rootView) + } + + containerViewController.addChild(contentViewController) + + let containerView = containerViewController.view! + let contentView = contentViewController.view! + + contentView.backgroundColor = .clear + contentView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(contentView) + + NSLayoutConstraint.activate([ + contentView.topAnchor.constraint(equalTo: containerView.topAnchor), + contentView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), + contentView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), + contentView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), + ]) + contentViewController.didMove(toParent: containerViewController) + + return containerViewController + } + + func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {} +} + +private final class ScreenCaptureProtectionContainerViewController: UIViewController { + private static var screenCaptureProtectionViewName = [ + "_", + "UI", + "Text", + "Layout", + "Canvas", + "View", + ].joined() + + // This property also maintains a strong reference to the `UITextField` instance + // (necessary since this instance isn't embedded into the view hierarchy). + private lazy var uiTextField: UITextField = { + let uiTextField = UITextField() + uiTextField.isSecureTextEntry = true + return uiTextField + }() + + private var screenCaptureProtectionView: UIView { + let viewName = Self.screenCaptureProtectionViewName + if let view: UIView = uiTextField.firstSubview(where: { NSStringFromClass(type(of: $0)) == viewName }) { + return view + } + + assertionFailure("Unable to find the view of type '\(viewName)' in the view hierarchy of '\(uiTextField)'") + + return uiTextField.subviews.first ?? UIView() + } + + override func loadView() { + view = screenCaptureProtectionView + } + + override func preferredContentSizeDidChange(forChildContentContainer container: any UIContentContainer) { + super.preferredContentSizeDidChange(forChildContentContainer: container) + if #available(iOS 16.0, *) { + preferredContentSize = container.preferredContentSize + } + } +} + +// MARK: - Convenience extensions + +private extension UIView { + func firstSubview(where predicate: (_ subview: UIView) -> Bool) -> T? { + for subview in subviews { + if predicate(subview) { + return subview as? T + } + + if let firstSubview: T? = subview.firstSubview(where: predicate) { + return firstSubview + } + } + + return nil + } +} diff --git a/Modules/TangemUIKitUtils/Extensions/UIApplication+.swift b/Modules/TangemUIUtils/Extensions/UIApplication+.swift similarity index 94% rename from Modules/TangemUIKitUtils/Extensions/UIApplication+.swift rename to Modules/TangemUIUtils/Extensions/UIApplication+.swift index 2ab8aeffa1..07e4f9d7df 100644 --- a/Modules/TangemUIKitUtils/Extensions/UIApplication+.swift +++ b/Modules/TangemUIUtils/Extensions/UIApplication+.swift @@ -1,6 +1,6 @@ // // UIApplication+.swift -// TangemUIKitUtils +// TangemUIUtils // // Created by Alexander Osokin on 09.12.2024. // Copyright © 2024 Tangem AG. All rights reserved. diff --git a/Modules/TangemUIKitUtils/Extensions/UIDevice+.swift b/Modules/TangemUIUtils/Extensions/UIDevice+.swift similarity index 94% rename from Modules/TangemUIKitUtils/Extensions/UIDevice+.swift rename to Modules/TangemUIUtils/Extensions/UIDevice+.swift index 6124fc06a3..f0b5c6f185 100644 --- a/Modules/TangemUIKitUtils/Extensions/UIDevice+.swift +++ b/Modules/TangemUIUtils/Extensions/UIDevice+.swift @@ -1,6 +1,6 @@ // // UIDevice+.swift -// TangemUIKitUtils +// TangemUIUtils // // Created by Alexander Osokin on 12.12.2024. // Copyright © 2024 Tangem AG. All rights reserved. diff --git a/Modules/TangemUIKitUtils/Extensions/UITextInputSecurityHardeningConfigurator.swift b/Modules/TangemUIUtils/Helpers/UITextInputSecurityHardeningConfigurator.swift similarity index 99% rename from Modules/TangemUIKitUtils/Extensions/UITextInputSecurityHardeningConfigurator.swift rename to Modules/TangemUIUtils/Helpers/UITextInputSecurityHardeningConfigurator.swift index 4cf4bb603d..3c36bed41e 100644 --- a/Modules/TangemUIKitUtils/Extensions/UITextInputSecurityHardeningConfigurator.swift +++ b/Modules/TangemUIUtils/Helpers/UITextInputSecurityHardeningConfigurator.swift @@ -1,6 +1,6 @@ // // UITextInputSecurityHardeningConfigurator.swift -// TangemUIKitUtils +// TangemUIUtils // // Created by Andrey Fedorov on 16.01.2025. // Copyright © 2025 Tangem AG. All rights reserved. diff --git a/Tangem/Common/Extensions/View+ReadContentOffset.swift b/Tangem/Common/Extensions/View+ReadContentOffset.swift index a96d843031..39252798f2 100644 --- a/Tangem/Common/Extensions/View+ReadContentOffset.swift +++ b/Tangem/Common/Extensions/View+ReadContentOffset.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI extension View { /// 1. Assign stable coordinate space to the scroll view itself. diff --git a/Tangem/Common/UI/CircleCheckmarkIcon.swift b/Tangem/Common/UI/CircleCheckmarkIcon.swift index 9a2ac89109..29e8b69592 100644 --- a/Tangem/Common/UI/CircleCheckmarkIcon.swift +++ b/Tangem/Common/UI/CircleCheckmarkIcon.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import TangemUI struct CircleCheckmarkIcon: View { let isSelected: Bool diff --git a/Tangem/Common/UI/ExpressCurrencyView/ExpressCurrencyView.swift b/Tangem/Common/UI/ExpressCurrencyView/ExpressCurrencyView.swift index b50c1f4d95..102859c83a 100644 --- a/Tangem/Common/UI/ExpressCurrencyView/ExpressCurrencyView.swift +++ b/Tangem/Common/UI/ExpressCurrencyView/ExpressCurrencyView.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import TangemUI struct ExpressCurrencyView: View { @ObservedObject private var viewModel: ExpressCurrencyViewModel diff --git a/Tangem/Common/Extensions/UIKit/PresentationConfigurationViewModifier.swift b/Tangem/Common/UI/Modifiers/PresentationConfigurationViewModifier.swift similarity index 100% rename from Tangem/Common/Extensions/UIKit/PresentationConfigurationViewModifier.swift rename to Tangem/Common/UI/Modifiers/PresentationConfigurationViewModifier.swift diff --git a/Tangem/Common/UI/Navigation/NavigationBar.swift b/Tangem/Common/UI/Navigation/NavigationBar.swift index fbdb2aa415..9e38b0fb6b 100644 --- a/Tangem/Common/UI/Navigation/NavigationBar.swift +++ b/Tangem/Common/UI/Navigation/NavigationBar.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct ArrowBack: View { let action: () -> Void diff --git a/Tangem/Common/UI/SendDecimalNumberTextField/SendDecimalNumberTextField.swift b/Tangem/Common/UI/SendDecimalNumberTextField/SendDecimalNumberTextField.swift index fceb78402d..1e3a9ac1fe 100644 --- a/Tangem/Common/UI/SendDecimalNumberTextField/SendDecimalNumberTextField.swift +++ b/Tangem/Common/UI/SendDecimalNumberTextField/SendDecimalNumberTextField.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import TangemUI /// Same as `DecimalNumberTextField` with support /// - `InitialFocusBehavior` diff --git a/Tangem/Common/UI/TextInputs/CustomTextField.swift b/Tangem/Common/UI/TextInputs/CustomTextField.swift index 21b94c2ca2..ac4459dec4 100644 --- a/Tangem/Common/UI/TextInputs/CustomTextField.swift +++ b/Tangem/Common/UI/TextInputs/CustomTextField.swift @@ -8,7 +8,7 @@ import Foundation import SwiftUI -import TangemUIKitUtils +import TangemUIUtils struct CustomTextField: UIViewRepresentable { class Coordinator: NSObject, UITextFieldDelegate { diff --git a/Tangem/Modules/ExpressView/ExpressView.swift b/Tangem/Modules/ExpressView/ExpressView.swift index bc1433e68e..fce71b69a0 100644 --- a/Tangem/Modules/ExpressView/ExpressView.swift +++ b/Tangem/Modules/ExpressView/ExpressView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct ExpressView: View { @ObservedObject private var viewModel: ExpressViewModel diff --git a/Tangem/Modules/Main/MainFooterView/Empty/EmptyMainFooterView.swift b/Tangem/Modules/Main/MainFooterView/Empty/EmptyMainFooterView.swift index 97f7c29edd..058fa82048 100644 --- a/Tangem/Modules/Main/MainFooterView/Empty/EmptyMainFooterView.swift +++ b/Tangem/Modules/Main/MainFooterView/Empty/EmptyMainFooterView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import TangemUIKitUtils +import TangemUIUtils struct EmptyMainFooterView: View { private var footerHeight: CGFloat { diff --git a/Tangem/Modules/Main/MainFooterView/MainBottomSheet/MainBottomSheetFooterView.swift b/Tangem/Modules/Main/MainFooterView/MainBottomSheet/MainBottomSheetFooterView.swift index f261ad9dec..a80634f1bf 100644 --- a/Tangem/Modules/Main/MainFooterView/MainBottomSheet/MainBottomSheetFooterView.swift +++ b/Tangem/Modules/Main/MainFooterView/MainBottomSheet/MainBottomSheetFooterView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import TangemUIKitUtils +import TangemUIUtils struct MainBottomSheetFooterView: View { @ObservedObject var viewModel: MainBottomSheetFooterViewModel diff --git a/Tangem/Modules/Main/MainHeaderView/MainHeaderView.swift b/Tangem/Modules/Main/MainHeaderView/MainHeaderView.swift index d2157b5fcc..904f05f95b 100644 --- a/Tangem/Modules/Main/MainHeaderView/MainHeaderView.swift +++ b/Tangem/Modules/Main/MainHeaderView/MainHeaderView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct MainHeaderView: View { @ObservedObject var viewModel: MainHeaderViewModel diff --git a/Tangem/Modules/Main/UIComponents/MainBottomSheetHintView.swift b/Tangem/Modules/Main/UIComponents/MainBottomSheetHintView.swift index 69da641696..a543533c4e 100644 --- a/Tangem/Modules/Main/UIComponents/MainBottomSheetHintView.swift +++ b/Tangem/Modules/Main/UIComponents/MainBottomSheetHintView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct MainBottomSheetHintView: View { let isDraggingHorizontally: Bool diff --git a/Tangem/Modules/Markets/GenerateAddressesView/GenerateAddressesView.swift b/Tangem/Modules/Markets/GenerateAddressesView/GenerateAddressesView.swift index 44451f2597..7af4fa10e9 100644 --- a/Tangem/Modules/Markets/GenerateAddressesView/GenerateAddressesView.swift +++ b/Tangem/Modules/Markets/GenerateAddressesView/GenerateAddressesView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import TangemUIKitUtils +import TangemUIUtils struct GenerateAddressesView: View { let viewModel: GenerateAddressesViewModel diff --git a/Tangem/Modules/Markets/MarketsTokenDetails/MarketsTokenDetailsView.swift b/Tangem/Modules/Markets/MarketsTokenDetails/MarketsTokenDetailsView.swift index 8c7f4c326e..516a31e14e 100644 --- a/Tangem/Modules/Markets/MarketsTokenDetails/MarketsTokenDetailsView.swift +++ b/Tangem/Modules/Markets/MarketsTokenDetails/MarketsTokenDetailsView.swift @@ -8,6 +8,7 @@ import SwiftUI import UIKit +import TangemUI struct MarketsTokenDetailsView: View { @ObservedObject var viewModel: MarketsTokenDetailsViewModel diff --git a/Tangem/Modules/Markets/MarketsTokenDetails/Subviews/ExchangesList/MarketsTokenDetailsExchangesListView.swift b/Tangem/Modules/Markets/MarketsTokenDetails/Subviews/ExchangesList/MarketsTokenDetailsExchangesListView.swift index c93ed66e00..6f31872047 100644 --- a/Tangem/Modules/Markets/MarketsTokenDetails/Subviews/ExchangesList/MarketsTokenDetailsExchangesListView.swift +++ b/Tangem/Modules/Markets/MarketsTokenDetails/Subviews/ExchangesList/MarketsTokenDetailsExchangesListView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct MarketsTokenDetailsExchangesListView: View { @ObservedObject var viewModel: MarketsTokenDetailsExchangesListViewModel diff --git a/Tangem/Modules/Markets/MarketsTokenDetails/Subviews/MarketsPortfolioContainerView/MarketsPortfolioTokenItemView.swift b/Tangem/Modules/Markets/MarketsTokenDetails/Subviews/MarketsPortfolioContainerView/MarketsPortfolioTokenItemView.swift index 2933eb30eb..0a93b740b6 100644 --- a/Tangem/Modules/Markets/MarketsTokenDetails/Subviews/MarketsPortfolioContainerView/MarketsPortfolioTokenItemView.swift +++ b/Tangem/Modules/Markets/MarketsTokenDetails/Subviews/MarketsPortfolioContainerView/MarketsPortfolioTokenItemView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct MarketsPortfolioTokenItemView: View { @ObservedObject var viewModel: MarketsPortfolioTokenItemViewModel diff --git a/Tangem/Modules/Markets/TokenList/MarketsView.swift b/Tangem/Modules/Markets/TokenList/MarketsView.swift index 7ae2e05f55..cfe4a43669 100644 --- a/Tangem/Modules/Markets/TokenList/MarketsView.swift +++ b/Tangem/Modules/Markets/TokenList/MarketsView.swift @@ -9,6 +9,7 @@ import SwiftUI import Combine import BlockchainSdk +import TangemUI struct MarketsView: View { @ObservedObject var viewModel: MarketsViewModel diff --git a/Tangem/Modules/Markets/TokensNetworkSelector/MarketsTokensNetworkSelectorItemView.swift b/Tangem/Modules/Markets/TokensNetworkSelector/MarketsTokensNetworkSelectorItemView.swift index 21578cc722..bacbc8436c 100644 --- a/Tangem/Modules/Markets/TokensNetworkSelector/MarketsTokensNetworkSelectorItemView.swift +++ b/Tangem/Modules/Markets/TokensNetworkSelector/MarketsTokensNetworkSelectorItemView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct MarketsTokensNetworkSelectorItemView: View { @ObservedObject var viewModel: MarketsTokensNetworkSelectorItemViewModel diff --git a/Tangem/Modules/Onboarding/Note/SingleCardOnboardingView.swift b/Tangem/Modules/Onboarding/Note/SingleCardOnboardingView.swift index a19ab2a125..608da93169 100644 --- a/Tangem/Modules/Onboarding/Note/SingleCardOnboardingView.swift +++ b/Tangem/Modules/Onboarding/Note/SingleCardOnboardingView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct SingleCardOnboardingView: View { @ObservedObject var viewModel: SingleCardOnboardingViewModel diff --git a/Tangem/Modules/Onboarding/Twins/TwinsOnboardingView.swift b/Tangem/Modules/Onboarding/Twins/TwinsOnboardingView.swift index 18714a8f5a..871d5e75f2 100644 --- a/Tangem/Modules/Onboarding/Twins/TwinsOnboardingView.swift +++ b/Tangem/Modules/Onboarding/Twins/TwinsOnboardingView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct TwinsOnboardingView: View { @ObservedObject var viewModel: TwinsOnboardingViewModel diff --git a/Tangem/Modules/Onboarding/Views/Animators/CardStackAnimator.swift b/Tangem/Modules/Onboarding/Views/Animators/CardStackAnimator.swift index 17b08201b3..a8b6db9c4f 100644 --- a/Tangem/Modules/Onboarding/Views/Animators/CardStackAnimator.swift +++ b/Tangem/Modules/Onboarding/Views/Animators/CardStackAnimator.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct CardsStackAnimatorSettings { let topCardSize: CGSize diff --git a/Tangem/Modules/Onboarding/Views/Animators/FanStackCalculator.swift b/Tangem/Modules/Onboarding/Views/Animators/FanStackCalculator.swift index f96fb65030..6e14dfc20c 100644 --- a/Tangem/Modules/Onboarding/Views/Animators/FanStackCalculator.swift +++ b/Tangem/Modules/Onboarding/Views/Animators/FanStackCalculator.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct FanStackCalculatorSettings { let cardsSize: CGSize diff --git a/Tangem/Modules/Onboarding/Views/ProgressBar/Checkmarks/OnboardingProgressCheckmarksView.swift b/Tangem/Modules/Onboarding/Views/ProgressBar/Checkmarks/OnboardingProgressCheckmarksView.swift index 85e36d8b0e..b134bd39a9 100644 --- a/Tangem/Modules/Onboarding/Views/ProgressBar/Checkmarks/OnboardingProgressCheckmarksView.swift +++ b/Tangem/Modules/Onboarding/Views/ProgressBar/Checkmarks/OnboardingProgressCheckmarksView.swift @@ -8,6 +8,7 @@ import SwiftUI import Combine +import TangemUI struct OnboardingProgressCheckmarksView: View { var numberOfSteps: Int diff --git a/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseGenerateView/OnboardingSeedPhraseGenerateView.swift b/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseGenerateView/OnboardingSeedPhraseGenerateView.swift index 8dc4f65574..80ab47db0d 100644 --- a/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseGenerateView/OnboardingSeedPhraseGenerateView.swift +++ b/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseGenerateView/OnboardingSeedPhraseGenerateView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct OnboardingSeedPhraseGenerateView: View { @ObservedObject var viewModel: OnboardingSeedPhraseGenerateViewModel @@ -106,9 +107,21 @@ struct OnboardingSeedPhraseGenerateView: View { Text("\(index + 1).\t") .style(Fonts.Regular.subheadline, color: Colors.Text.tertiary) - Text("\(viewModel.words[index])") + let wordView = Text("\(viewModel.words[index])") .style(Fonts.Bold.subheadline, color: Colors.Text.primary1) + // The order of the `fixedSize` modifier must be different on iOS 15 and iOS 16+, + // otherwise the layout will be broken + if #available(iOS 16.0, *) { + wordView + .screenCaptureProtection() + .fixedSize() + } else { + wordView + .fixedSize() + .screenCaptureProtection() + } + Spacer() } } diff --git a/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseImportView/OnboardingSeedPhraseImportView.swift b/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseImportView/OnboardingSeedPhraseImportView.swift index 132e4d7120..068c34fad9 100644 --- a/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseImportView/OnboardingSeedPhraseImportView.swift +++ b/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseImportView/OnboardingSeedPhraseImportView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct OnboardingSeedPhraseImportView: View { @ObservedObject var viewModel: OnboardingSeedPhraseImportViewModel @@ -26,6 +27,7 @@ struct OnboardingSeedPhraseImportView: View { inputProcessor: viewModel.inputProcessor, shouldBecomeFirstResponderAtStart: true ) + .screenCaptureProtection() .padding(.horizontal, 16) .padding(.vertical, 10) .background(Colors.Field.primary) @@ -112,6 +114,7 @@ struct OnboardingSeedPhraseImportView: View { placeholder: Localization.sendOptionalField ) .setAutocapitalizationType(.none) + .screenCaptureProtection() } .padding(.horizontal, 14) .padding(.vertical, 12) diff --git a/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseUserValidationView/OnboardingSeedPhraseUserValidationView.swift b/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseUserValidationView/OnboardingSeedPhraseUserValidationView.swift index 621b9e6789..8bcd78ee94 100644 --- a/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseUserValidationView/OnboardingSeedPhraseUserValidationView.swift +++ b/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseUserValidationView/OnboardingSeedPhraseUserValidationView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct OnboardingSeedPhraseUserValidationView: View { @ObservedObject var viewModel: OnboardingSeedPhraseUserValidationViewModel @@ -98,30 +99,34 @@ private struct WordInputView: View { ) .frame(width: 38, alignment: .leading) .padding(.leading, 16) - - CustomTextField( - text: text, - isResponder: $isResponder, - actionButtonTapped: .constant(false), - clearsOnBeginEditing: false, - handleKeyboard: true, - keyboard: .asciiCapable, - clearButtonMode: .never, - textColor: UIColor(hasError ? Colors.Text.warning : Colors.Text.primary1), - font: UIFonts.Regular.body, - placeholder: "", - isEnabled: true - ) - .setAutocapitalizationType(.none) - .padding(.vertical, 12) - - if isResponder ?? false { - Button(action: { text.wrappedValue = "" }) { - Assets.clear.image - .foregroundColor(Colors.Icon.informative) - .padding(.horizontal, 16) + .layoutPriority(1000.0) + + HStack(spacing: 0.0) { + CustomTextField( + text: text, + isResponder: $isResponder, + actionButtonTapped: .constant(false), + clearsOnBeginEditing: false, + handleKeyboard: true, + keyboard: .asciiCapable, + clearButtonMode: .never, + textColor: UIColor(hasError ? Colors.Text.warning : Colors.Text.primary1), + font: UIFonts.Regular.body, + placeholder: "", + isEnabled: true + ) + .setAutocapitalizationType(.none) + .padding(.vertical, 12) + + if isResponder ?? false { + Button(action: { text.wrappedValue = "" }) { + Assets.clear.image + .foregroundColor(Colors.Icon.informative) + .padding(.horizontal, 16) + } } } + .screenCaptureProtection() } .frame(minHeight: 46) .background(Colors.Field.primary) diff --git a/Tangem/Modules/Onboarding/Views/SeedPhrase/SeedPhraseTextView.swift b/Tangem/Modules/Onboarding/Views/SeedPhrase/SeedPhraseTextView.swift index 30f48550c7..5c0be79216 100644 --- a/Tangem/Modules/Onboarding/Views/SeedPhrase/SeedPhraseTextView.swift +++ b/Tangem/Modules/Onboarding/Views/SeedPhrase/SeedPhraseTextView.swift @@ -9,7 +9,7 @@ import Foundation import SwiftUI import Combine -import TangemUIKitUtils +import TangemUIUtils struct SeedPhraseTextView: UIViewRepresentable { private unowned var inputProcessor: SeedPhraseInputProcessor diff --git a/Tangem/Modules/Onboarding/Wallet/WalletOnboardingView.swift b/Tangem/Modules/Onboarding/Wallet/WalletOnboardingView.swift index ce813432de..73a5d347f1 100644 --- a/Tangem/Modules/Onboarding/Wallet/WalletOnboardingView.swift +++ b/Tangem/Modules/Onboarding/Wallet/WalletOnboardingView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct WalletOnboardingView: View { @ObservedObject var viewModel: WalletOnboardingViewModel diff --git a/Tangem/Modules/OrganizeTokens/ListFooter/OrganizeTokensListFooter.swift b/Tangem/Modules/OrganizeTokens/ListFooter/OrganizeTokensListFooter.swift index 7959f99dd1..df47d574ff 100644 --- a/Tangem/Modules/OrganizeTokens/ListFooter/OrganizeTokensListFooter.swift +++ b/Tangem/Modules/OrganizeTokens/ListFooter/OrganizeTokensListFooter.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct OrganizeTokensListFooter: View { let viewModel: OrganizeTokensViewModel diff --git a/Tangem/Modules/OrganizeTokens/OrganizeTokensView.swift b/Tangem/Modules/OrganizeTokens/OrganizeTokensView.swift index dcf2df266c..bcf4025354 100644 --- a/Tangem/Modules/OrganizeTokens/OrganizeTokensView.swift +++ b/Tangem/Modules/OrganizeTokens/OrganizeTokensView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct OrganizeTokensView: View { // MARK: - Model diff --git a/Tangem/Modules/ResetToFactory/ResetToFactoryView.swift b/Tangem/Modules/ResetToFactory/ResetToFactoryView.swift index 62a8fa39a9..15cab14bfc 100644 --- a/Tangem/Modules/ResetToFactory/ResetToFactoryView.swift +++ b/Tangem/Modules/ResetToFactory/ResetToFactoryView.swift @@ -7,7 +7,7 @@ // import SwiftUI -import TangemUIKitUtils +import TangemUIUtils struct ResetToFactoryView: View { @ObservedObject private var viewModel: ResetToFactoryViewModel diff --git a/Tangem/Modules/Send/UI/Amount/SendAmountCompactView/SendAmountCompactView.swift b/Tangem/Modules/Send/UI/Amount/SendAmountCompactView/SendAmountCompactView.swift index df9c429601..cba222be51 100644 --- a/Tangem/Modules/Send/UI/Amount/SendAmountCompactView/SendAmountCompactView.swift +++ b/Tangem/Modules/Send/UI/Amount/SendAmountCompactView/SendAmountCompactView.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import TangemUI struct SendAmountCompactView: View { @ObservedObject var viewModel: SendAmountCompactViewModel diff --git a/Tangem/Modules/Send/UI/Destination/AddressView/AddressTextView.swift b/Tangem/Modules/Send/UI/Destination/AddressView/AddressTextView.swift index ace6683278..45e44946eb 100644 --- a/Tangem/Modules/Send/UI/Destination/AddressView/AddressTextView.swift +++ b/Tangem/Modules/Send/UI/Destination/AddressView/AddressTextView.swift @@ -9,6 +9,7 @@ import Foundation import UIKit import SwiftUI +import TangemUI // MARK: - SwiftUI view diff --git a/Tangem/Modules/Send/UI/Destination/SendDestinationCompactView/SendDestinationCompactView.swift b/Tangem/Modules/Send/UI/Destination/SendDestinationCompactView/SendDestinationCompactView.swift index 3cc07e8ed6..ad6f4eb83a 100644 --- a/Tangem/Modules/Send/UI/Destination/SendDestinationCompactView/SendDestinationCompactView.swift +++ b/Tangem/Modules/Send/UI/Destination/SendDestinationCompactView/SendDestinationCompactView.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import TangemUI struct SendDestinationCompactView: View { @ObservedObject var viewModel: SendDestinationCompactViewModel diff --git a/Tangem/Modules/Send/UI/Fee/SendFeeCompactView/SendFeeCompactView.swift b/Tangem/Modules/Send/UI/Fee/SendFeeCompactView/SendFeeCompactView.swift index 073d449dd8..c91d43054a 100644 --- a/Tangem/Modules/Send/UI/Fee/SendFeeCompactView/SendFeeCompactView.swift +++ b/Tangem/Modules/Send/UI/Fee/SendFeeCompactView/SendFeeCompactView.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import TangemUI struct SendFeeCompactView: View { @ObservedObject var viewModel: SendFeeCompactViewModel diff --git a/Tangem/Modules/Send/UI/Validators/StakingValidatorsCompactView/StakingValidatorsCompactView.swift b/Tangem/Modules/Send/UI/Validators/StakingValidatorsCompactView/StakingValidatorsCompactView.swift index 5f168f7aff..ada79c6a40 100644 --- a/Tangem/Modules/Send/UI/Validators/StakingValidatorsCompactView/StakingValidatorsCompactView.swift +++ b/Tangem/Modules/Send/UI/Validators/StakingValidatorsCompactView/StakingValidatorsCompactView.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import TangemUI struct StakingValidatorsCompactView: View { @ObservedObject var viewModel: StakingValidatorsCompactViewModel diff --git a/Tangem/Modules/StakingDetails/StakingDetailsView.swift b/Tangem/Modules/StakingDetails/StakingDetailsView.swift index 47d668fdd2..6a4762412e 100644 --- a/Tangem/Modules/StakingDetails/StakingDetailsView.swift +++ b/Tangem/Modules/StakingDetails/StakingDetailsView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct StakingDetailsView: View { @ObservedObject var viewModel: StakingDetailsViewModel diff --git a/Tangem/RootViewControllerFactory.swift b/Tangem/RootViewControllerFactory.swift index 577b9aebca..66a72e048b 100644 --- a/Tangem/RootViewControllerFactory.swift +++ b/Tangem/RootViewControllerFactory.swift @@ -9,7 +9,7 @@ import Foundation import UIKit import SwiftUI -import TangemUIKitUtils +import TangemUIUtils struct RootViewControllerFactory { func makeRootViewController(for rootView: some View, window: UIWindow) -> UIViewController { diff --git a/Tangem/UIComponents/BottomSheet/BottomSheetContainer.swift b/Tangem/UIComponents/BottomSheet/BottomSheetContainer.swift index a7ddb05df8..0aba87e408 100644 --- a/Tangem/UIComponents/BottomSheet/BottomSheetContainer.swift +++ b/Tangem/UIComponents/BottomSheet/BottomSheetContainer.swift @@ -8,7 +8,8 @@ import Foundation import SwiftUI -import TangemUIKitUtils +import TangemUI +import TangemUIUtils struct BottomSheetContainer: View { @ObservedObject private var stateObject: StateObject diff --git a/Tangem/UIComponents/CardsInfoPagerView/CardsInfoPagerView.swift b/Tangem/UIComponents/CardsInfoPagerView/CardsInfoPagerView.swift index f8650d84f7..486d181888 100644 --- a/Tangem/UIComponents/CardsInfoPagerView/CardsInfoPagerView.swift +++ b/Tangem/UIComponents/CardsInfoPagerView/CardsInfoPagerView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct CardsInfoPagerView< Data, ID, Header, Body, BottomOverlay diff --git a/Tangem/UIComponents/Common/CustomSearchBar.swift b/Tangem/UIComponents/Common/CustomSearchBar.swift index f5700cdc2b..c7c4f57067 100644 --- a/Tangem/UIComponents/Common/CustomSearchBar.swift +++ b/Tangem/UIComponents/Common/CustomSearchBar.swift @@ -7,7 +7,7 @@ // import SwiftUI -import TangemUIKitUtils +import TangemUIUtils struct CustomSearchBar: View { @Binding var searchText: String diff --git a/Tangem/UIComponents/DescriptionBottomSheet/TokenDescriptionBottomSheetView.swift b/Tangem/UIComponents/DescriptionBottomSheet/TokenDescriptionBottomSheetView.swift index 10f2b86484..27e79d58b4 100644 --- a/Tangem/UIComponents/DescriptionBottomSheet/TokenDescriptionBottomSheetView.swift +++ b/Tangem/UIComponents/DescriptionBottomSheet/TokenDescriptionBottomSheetView.swift @@ -8,7 +8,7 @@ import SwiftUI import MarkdownUI -import TangemUIKitUtils +import TangemUIUtils struct TokenDescriptionBottomSheetView: View { let info: DescriptionBottomSheetInfo diff --git a/Tangem/UIComponents/DetentBottonSheet/AdaptiveSizeSheet/View+AdaptiveSizeSheetModifier.swift b/Tangem/UIComponents/DetentBottonSheet/AdaptiveSizeSheet/View+AdaptiveSizeSheetModifier.swift index ed8f960fe0..eec2a6b4c0 100644 --- a/Tangem/UIComponents/DetentBottonSheet/AdaptiveSizeSheet/View+AdaptiveSizeSheetModifier.swift +++ b/Tangem/UIComponents/DetentBottonSheet/AdaptiveSizeSheet/View+AdaptiveSizeSheetModifier.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct AdaptiveSizeSheetModifier: ViewModifier { @StateObject private var viewModel = AdaptiveSizeSheetViewModel() diff --git a/Tangem/UIComponents/ManageTokensListView/ListItems/ManageTokensItemNetworkSelectorView.swift b/Tangem/UIComponents/ManageTokensListView/ListItems/ManageTokensItemNetworkSelectorView.swift index 484daaf32e..2254ddd60b 100644 --- a/Tangem/UIComponents/ManageTokensListView/ListItems/ManageTokensItemNetworkSelectorView.swift +++ b/Tangem/UIComponents/ManageTokensListView/ListItems/ManageTokensItemNetworkSelectorView.swift @@ -8,6 +8,7 @@ import SwiftUI import BlockchainSdk +import TangemUI struct ManageTokensItemNetworkSelectorView: View { @ObservedObject var viewModel: ManageTokensItemNetworkSelectorViewModel diff --git a/Tangem/UIComponents/OverlayContentContainer/UIKit/OverlayContentContainerViewController.swift b/Tangem/UIComponents/OverlayContentContainer/UIKit/OverlayContentContainerViewController.swift index 9184ae6236..e2f1568d7d 100644 --- a/Tangem/UIComponents/OverlayContentContainer/UIKit/OverlayContentContainerViewController.swift +++ b/Tangem/UIComponents/OverlayContentContainer/UIKit/OverlayContentContainerViewController.swift @@ -8,7 +8,7 @@ import Foundation import UIKit -import TangemUIKitUtils +import TangemUIUtils final class OverlayContentContainerViewController: UIViewController { // MARK: - Dependencies diff --git a/Tangem/UIComponents/ReceiveBottomSheetView/ReceiveBottomSheetView.swift b/Tangem/UIComponents/ReceiveBottomSheetView/ReceiveBottomSheetView.swift index 2ca12d031e..a51e60bfbc 100644 --- a/Tangem/UIComponents/ReceiveBottomSheetView/ReceiveBottomSheetView.swift +++ b/Tangem/UIComponents/ReceiveBottomSheetView/ReceiveBottomSheetView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct ReceiveBottomSheetView: View { @ObservedObject var viewModel: ReceiveBottomSheetViewModel diff --git a/Tangem/UIComponents/SegmentPickerView/SegmentedPickerView.swift b/Tangem/UIComponents/SegmentPickerView/SegmentedPickerView.swift index 218787dfa5..0544f29580 100644 --- a/Tangem/UIComponents/SegmentPickerView/SegmentedPickerView.swift +++ b/Tangem/UIComponents/SegmentPickerView/SegmentedPickerView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI /* https://github.com/Inxel/CustomizableSegmentedControl diff --git a/Tangem/UIComponents/TokenItemView/TokenItemView.swift b/Tangem/UIComponents/TokenItemView/TokenItemView.swift index 7804ee9d4a..cf01b6892d 100644 --- a/Tangem/UIComponents/TokenItemView/TokenItemView.swift +++ b/Tangem/UIComponents/TokenItemView/TokenItemView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TangemUI struct TokenItemView: View { @ObservedObject private var viewModel: TokenItemViewModel diff --git a/TangemApp.xcodeproj/project.pbxproj b/TangemApp.xcodeproj/project.pbxproj index 692085151a..ff8340fccb 100644 --- a/TangemApp.xcodeproj/project.pbxproj +++ b/TangemApp.xcodeproj/project.pbxproj @@ -1726,7 +1726,6 @@ B6323E382C61D38F00C1CE60 /* MarketsTokenDetailsDateHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6323E372C61D38F00C1CE60 /* MarketsTokenDetailsDateHelper.swift */; }; B6323E3A2C61D8FD00C1CE60 /* MarketsTokenDetailsPriceInfoHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6323E392C61D8FD00C1CE60 /* MarketsTokenDetailsPriceInfoHelper.swift */; }; B63442612AFE90A700C87481 /* CardsInfoPagerSwipeDiscoveryAnimationTrigger.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63442602AFE90A700C87481 /* CardsInfoPagerSwipeDiscoveryAnimationTrigger.swift */; }; - B63457772A3A097C00E164C5 /* View+ReadGeometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63457762A3A097C00E164C5 /* View+ReadGeometry.swift */; }; B6364F882ACEE9AC00D615B5 /* EmptyMainFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6364F872ACEE9AC00D615B5 /* EmptyMainFooterView.swift */; }; B63B63BA2A44012D00A7CECF /* OrganizeTokensListHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63B63B92A44012D00A7CECF /* OrganizeTokensListHeader.swift */; }; B63B63BD2A44013E00A7CECF /* OrganizeTokensListFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63B63BC2A44013E00A7CECF /* OrganizeTokensListFooter.swift */; }; @@ -4928,7 +4927,6 @@ B6323E372C61D38F00C1CE60 /* MarketsTokenDetailsDateHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketsTokenDetailsDateHelper.swift; sourceTree = ""; }; B6323E392C61D8FD00C1CE60 /* MarketsTokenDetailsPriceInfoHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketsTokenDetailsPriceInfoHelper.swift; sourceTree = ""; }; B63442602AFE90A700C87481 /* CardsInfoPagerSwipeDiscoveryAnimationTrigger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsInfoPagerSwipeDiscoveryAnimationTrigger.swift; sourceTree = ""; }; - B63457762A3A097C00E164C5 /* View+ReadGeometry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ReadGeometry.swift"; sourceTree = ""; }; B6364F872ACEE9AC00D615B5 /* EmptyMainFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyMainFooterView.swift; sourceTree = ""; }; B63B63B92A44012D00A7CECF /* OrganizeTokensListHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganizeTokensListHeader.swift; sourceTree = ""; }; B63B63BC2A44013E00A7CECF /* OrganizeTokensListFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganizeTokensListFooter.swift; sourceTree = ""; }; @@ -7256,7 +7254,6 @@ DAF97FC82BAAF2CC006D9A44 /* Locale+.swift */, 5D06E03F250A5D54004218D0 /* NSRegualrExpression+.swift */, 5D80ED462550186A0008DEF0 /* View+.swift */, - B63457762A3A097C00E164C5 /* View+ReadGeometry.swift */, B687E9482A2D881C00BFF604 /* View+ReadContentOffset.swift */, B0C8A0D32562C86A00DEEAC7 /* View+PreviewDevice.swift */, B65108B22CAC2A8100690C22 /* ShapeStyle+.swift */, @@ -8279,7 +8276,6 @@ B6176A792A5B743A0062C399 /* CGRect+.swift */, B6FCEE722C40E16100CA9252 /* CGAffineTransform+.swift */, B6B1CCC92C460BB9006C1B44 /* UIPanGestureRecognizer+.swift */, - 2D2ACE192B30FAA90004CBB6 /* PresentationConfigurationViewModifier.swift */, EF033B172B8631C700A71600 /* UIResponder+.swift */, B6FCEE702C40E14300CA9252 /* UIScrollView+.swift */, B6FFADE92C5D67E900B43A56 /* DGCharts.ChartViewBase+.swift */, @@ -8426,7 +8422,6 @@ children = ( DC2891772CD9107E00F57F59 /* CloseToolbarButton */, DCC05A5E2CD17DE6004CE6A4 /* TokenSelectorView */, - DC77F2542CD508D9001B2929 /* SUILabel.swift */, EF0E1DAE2CE3A2A5003D47AA /* ProgressDots */, B0340B9C2C50C7B2008FF6FC /* AnimationModifiers */, B0FF12662C4A811000C81ED8 /* EnvironmentKeys */, @@ -8469,6 +8464,7 @@ 2DC46C372C98022500749F7C /* Shapes */, 2DADFF9E2C98A9F30029F390 /* Tooltip */, 2DE0BA972CA930CE002C09D9 /* CommonHeaders */, + DC77F2542CD508D9001B2929 /* SUILabel.swift */, ); path = UIComponents; sourceTree = ""; @@ -8860,6 +8856,7 @@ B61980112AB98ACE00153886 /* HighlightableViewModifier.swift */, B62EE31D2B28A0FE006BA412 /* AppStoreReviewModifier.swift */, B6B1BC282C6CCE88003EDB47 /* IntrospectResponderChainViewModifier.swift */, + 2D2ACE192B30FAA90004CBB6 /* PresentationConfigurationViewModifier.swift */, ); path = Modifiers; sourceTree = ""; @@ -18536,7 +18533,6 @@ DC7D3A0529E06334007BCD23 /* GenericTangemSdkFactory.swift in Sources */, DAE6F76D2800011400411F45 /* AppError.swift in Sources */, DC2891AB2CDAE93C00F57F59 /* BuyActionButtonViewModel.swift in Sources */, - B63457772A3A097C00E164C5 /* View+ReadGeometry.swift in Sources */, B690FC652C91CBA800D8683B /* MarketsBaseViewModel.swift in Sources */, DCC05A602CD17DFD004CE6A4 /* TokenSelectorView.swift in Sources */, 2DBE29C42B3C4A8100109D5E /* View+DetentBottomSheet.swift in Sources */, From 1b7ba96f2958e0502450f7570d52e217fa1cfda5 Mon Sep 17 00:00:00 2001 From: Aleksei Lobankov Date: Wed, 22 Jan 2025 17:39:25 +0300 Subject: [PATCH 6/8] IOS-9003 Dione nownodes handling added. (#4522) --- .../Network/EthereumJsonRpcProvider.swift | 15 ++++++------ .../Ethereum/Network/EthereumTarget.swift | 23 +++++++++++++++---- .../NowNodesAPIKeysInfoProvider.swift | 2 +- .../NowNodes/NowNodesAPIResolver.swift | 2 ++ .../Common/NetworkProviderAssembly.swift | 2 +- 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/BlockchainSdk/Blockchains/Ethereum/Network/EthereumJsonRpcProvider.swift b/BlockchainSdk/Blockchains/Ethereum/Network/EthereumJsonRpcProvider.swift index 9adf60f8e2..af74f86ea6 100644 --- a/BlockchainSdk/Blockchains/Ethereum/Network/EthereumJsonRpcProvider.swift +++ b/BlockchainSdk/Blockchains/Ethereum/Network/EthereumJsonRpcProvider.swift @@ -12,17 +12,16 @@ import BigInt import Moya import TangemNetworkUtils -class EthereumJsonRpcProvider: HostProvider { - let url: URL +final class EthereumJsonRpcProvider: HostProvider { + private let node: NodeInfo + private let provider: NetworkProvider var host: String { - url.hostOrUnknown + node.url.hostOrUnknown } - private let provider: NetworkProvider - - init(url: URL, configuration: NetworkProviderConfiguration) { - self.url = url + init(node: NodeInfo, configuration: NetworkProviderConfiguration) { + self.node = node provider = NetworkProvider(configuration: configuration) } @@ -63,7 +62,7 @@ class EthereumJsonRpcProvider: HostProvider { } private func requestPublisher(for targetType: EthereumTarget.EthereumTargetType) -> AnyPublisher { - let target = EthereumTarget(targetType: targetType, baseURL: url) + let target = EthereumTarget(targetType: targetType, node: node) return provider.requestPublisher(target) .filterSuccessfulStatusAndRedirectCodes() diff --git a/BlockchainSdk/Blockchains/Ethereum/Network/EthereumTarget.swift b/BlockchainSdk/Blockchains/Ethereum/Network/EthereumTarget.swift index 1ed823571a..e885b222f9 100644 --- a/BlockchainSdk/Blockchains/Ethereum/Network/EthereumTarget.swift +++ b/BlockchainSdk/Blockchains/Ethereum/Network/EthereumTarget.swift @@ -11,8 +11,12 @@ import Moya import TangemNetworkUtils struct EthereumTarget: TargetType { - let targetType: EthereumTargetType - let baseURL: URL + private let targetType: EthereumTargetType + private let node: NodeInfo + + var baseURL: URL { + node.url + } var path: String { return "" @@ -29,9 +33,18 @@ struct EthereumTarget: TargetType { } var headers: [String: String]? { - [ - "Content-Type": "application/json", - ] + var headers = ["Content-Type": "application/json"] + + if let headersKeyInfo = node.headers { + headers[headersKeyInfo.headerName] = headersKeyInfo.headerValue + } + + return headers + } + + init(targetType: EthereumTargetType, node: NodeInfo) { + self.targetType = targetType + self.node = node } } diff --git a/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIKeysInfoProvider.swift b/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIKeysInfoProvider.swift index 5cc5679f0e..efac39c8dd 100644 --- a/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIKeysInfoProvider.swift +++ b/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIKeysInfoProvider.swift @@ -12,7 +12,7 @@ struct NowNodesAPIKeysInfoProvider { let apiKey: String func apiKeys(for blockchain: Blockchain) -> APIHeaderKeyInfo? { switch blockchain { - case .xrp, .tron, .algorand, .aptos, .solana: + case .xrp, .tron, .algorand, .aptos, .solana, .odysseyChain: return .init( headerName: Constants.nowNodesApiKeyHeaderName, headerValue: apiKey diff --git a/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIResolver.swift b/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIResolver.swift index 57c4c305a6..9cef00ccae 100644 --- a/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIResolver.swift +++ b/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIResolver.swift @@ -94,6 +94,8 @@ struct NowNodesAPIResolver { link = "https://sui.nownodes.io/\(apiKey)" case .tezos: link = "https://xtz.nownodes.io/\(apiKey)" + case .odysseyChain: + link = "https://odyssey.nownodes.io/ext/bc/D/rpc" default: return nil } diff --git a/BlockchainSdk/Common/NetworkProviderAssembly.swift b/BlockchainSdk/Common/NetworkProviderAssembly.swift index 34002d0672..161a5dcb65 100644 --- a/BlockchainSdk/Common/NetworkProviderAssembly.swift +++ b/BlockchainSdk/Common/NetworkProviderAssembly.swift @@ -83,7 +83,7 @@ struct NetworkProviderAssembly { func makeEthereumJsonRpcProviders(with input: NetworkProviderAssemblyInput) -> [EthereumJsonRpcProvider] { return APIResolver(blockchain: input.blockchain, config: input.blockchainSdkConfig) .resolveProviders(apiInfos: input.apiInfo) { nodeInfo, _ in - EthereumJsonRpcProvider(url: nodeInfo.url, configuration: input.networkConfig) + EthereumJsonRpcProvider(node: nodeInfo, configuration: input.networkConfig) } } } From 64aebae32bc4192a3989132cc3aa83d607dcd8ba Mon Sep 17 00:00:00 2001 From: Andrey Fedorov Date: Wed, 22 Jan 2025 15:43:27 +0100 Subject: [PATCH 7/8] IOS-8992: Replace broken tab symbol with manual width calculation (#4524) Signed-off-by: Andrey Fedorov --- .../OnboardingSeedPhraseGenerateView.swift | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseGenerateView/OnboardingSeedPhraseGenerateView.swift b/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseGenerateView/OnboardingSeedPhraseGenerateView.swift index 80ab47db0d..3e5fee3f7c 100644 --- a/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseGenerateView/OnboardingSeedPhraseGenerateView.swift +++ b/Tangem/Modules/Onboarding/Views/SeedPhrase/OnboardingSeedPhraseGenerateView/OnboardingSeedPhraseGenerateView.swift @@ -12,6 +12,8 @@ import TangemUI struct OnboardingSeedPhraseGenerateView: View { @ObservedObject var viewModel: OnboardingSeedPhraseGenerateViewModel + @State var wordsColumnMaxWidth: CGFloat? + var body: some View { VStack(spacing: 0) { Picker("", selection: $viewModel.selectedLength, content: { @@ -104,8 +106,11 @@ struct OnboardingSeedPhraseGenerateView: View { VStack(alignment: .leading, spacing: verticalSpacing) { ForEach(indexRange, id: \.self) { index in HStack(alignment: .center, spacing: 0) { - Text("\(index + 1).\t") + Text("\(index + 1). ") // The space character after the dot is 'U+2009 THIN SPACE' .style(Fonts.Regular.subheadline, color: Colors.Text.tertiary) + .fixedSize() + .readGeometry(\.size.width, onChange: updateWordsColumnMaxWidth(width:)) + .frame(width: wordsColumnMaxWidth, alignment: .leading) let wordView = Text("\(viewModel.words[index])") .style(Fonts.Bold.subheadline, color: Colors.Text.primary1) @@ -127,6 +132,10 @@ struct OnboardingSeedPhraseGenerateView: View { } } } + + private func updateWordsColumnMaxWidth(width: CGFloat) { + wordsColumnMaxWidth = max(wordsColumnMaxWidth ?? .zero, width) + } } struct OnboardingSeedPhraseGenerateView_Previews: PreviewProvider { From 6d90cf4489e9a1b7fc59e239911bfbcf074700d6 Mon Sep 17 00:00:00 2001 From: Alexander Osokin <4981841+tureck1y@users.noreply.github.com> Date: Wed, 22 Jan 2025 15:41:17 +0000 Subject: [PATCH 8/8] IOS-8917 Fix animations and tokens inside onboarding (#4503) --- Tangem/Modules/App/AppCoordinator.swift | 16 ++++++++++------ Tangem/Modules/App/AppCoordinatorView.swift | 13 ++++++------- .../Modules/Welcome/WelcomeCoordinator.swift | 5 ++++- .../Welcome/WelcomeCoordinatorView.swift | 7 +++++-- .../WelcomeOnboardingView.swift | 18 +++++++++++------- 5 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Tangem/Modules/App/AppCoordinator.swift b/Tangem/Modules/App/AppCoordinator.swift index 2abca27db2..cda8127682 100644 --- a/Tangem/Modules/App/AppCoordinator.swift +++ b/Tangem/Modules/App/AppCoordinator.swift @@ -89,7 +89,7 @@ class AppCoordinator: CoordinatorObject { } private func setupLock() { - viewState = .lock + setState(.lock) } private func setupWelcome() { @@ -106,7 +106,7 @@ class AppCoordinator: CoordinatorObject { let welcomeCoordinator = WelcomeCoordinator(dismissAction: dismissAction) welcomeCoordinator.start(with: .init()) - viewState = .welcome(welcomeCoordinator) + setState(.welcome(welcomeCoordinator)) } private func setupAuth(unlockOnAppear: Bool) { @@ -124,7 +124,7 @@ class AppCoordinator: CoordinatorObject { let authCoordinator = AuthCoordinator(dismissAction: dismissAction) authCoordinator.start(with: .init(unlockOnAppear: unlockOnAppear)) - viewState = .auth(authCoordinator) + setState(.auth(authCoordinator)) } private func setupUncompletedBackup() { @@ -135,7 +135,7 @@ class AppCoordinator: CoordinatorObject { let uncompleteBackupCoordinator = UncompletedBackupCoordinator(dismissAction: dismissAction) uncompleteBackupCoordinator.start() - viewState = .uncompleteBackup(uncompleteBackupCoordinator) + setState(.uncompleteBackup(uncompleteBackupCoordinator)) } /// - Note: The coordinator is set up only once and only when the feature toggle is enabled. @@ -171,6 +171,10 @@ class AppCoordinator: CoordinatorObject { .assign(to: \.isOverlayContentContainerShown, on: self, ownership: .weak) .store(in: &bag) } + + private func setState(_ newViewState: AppCoordinator.ViewState) { + viewState = newViewState + } } // MARK: - Options @@ -229,7 +233,7 @@ extension AppCoordinator { let coordinator = OnboardingCoordinator(dismissAction: dismissAction) let options = OnboardingCoordinator.Options(input: input) coordinator.start(with: options) - viewState = .onboarding(coordinator) + setState(.onboarding(coordinator)) } func openMain(with userWalletModel: UserWalletModel) { @@ -237,7 +241,7 @@ extension AppCoordinator { let options = MainCoordinator.Options(userWalletModel: userWalletModel) coordinator.start(with: options) - viewState = .main(coordinator) + setState(.main(coordinator)) } } diff --git a/Tangem/Modules/App/AppCoordinatorView.swift b/Tangem/Modules/App/AppCoordinatorView.swift index 5d49fda035..f359a07051 100644 --- a/Tangem/Modules/App/AppCoordinatorView.swift +++ b/Tangem/Modules/App/AppCoordinatorView.swift @@ -51,28 +51,29 @@ struct AppCoordinatorView: CoordinatorView { @ViewBuilder private var content: some View { + // We need stack to force transition animation work ZStack { switch coordinator.viewState { case .welcome(let welcomeCoordinator): WelcomeCoordinatorView(coordinator: welcomeCoordinator) - .transition(.opacity) + .transition(.opacity.animation(.easeIn)) .navigationBarHidden(true) case .uncompleteBackup(let uncompletedBackupCoordinator): UncompletedBackupCoordinatorView(coordinator: uncompletedBackupCoordinator) - .transition(.opacity) + .transition(.opacity.animation(.easeIn)) .navigationBarHidden(true) case .auth(let authCoordinator): AuthCoordinatorView(coordinator: authCoordinator) .setNamespace(namespace) - .transition(.opacity) + .transition(.opacity.animation(.easeIn)) .navigationBarHidden(true) case .main(let mainCoordinator): MainCoordinatorView(coordinator: mainCoordinator) - .transition(.opacity) + .transition(.opacity.animation(.easeIn)) .navigationBarHidden(false) case .onboarding(let onboardingCoordinator): OnboardingCoordinatorView(coordinator: onboardingCoordinator) - .transition(.opacity) + .transition(.opacity.animation(.easeIn)) .navigationBarHidden(true) case .lock: LockView(usesNamespace: true) @@ -82,7 +83,5 @@ struct AppCoordinatorView: CoordinatorView { EmptyView() } } - // We need stack to force transition animation work - .animation(.easeIn, value: coordinator.viewState) } } diff --git a/Tangem/Modules/Welcome/WelcomeCoordinator.swift b/Tangem/Modules/Welcome/WelcomeCoordinator.swift index da2268653d..dfba18e204 100644 --- a/Tangem/Modules/Welcome/WelcomeCoordinator.swift +++ b/Tangem/Modules/Welcome/WelcomeCoordinator.swift @@ -8,6 +8,7 @@ import Foundation import Combine +import SwiftUI import TangemSdk class WelcomeCoordinator: CoordinatorObject { @@ -76,7 +77,9 @@ class WelcomeCoordinator: CoordinatorObject { } let dismissAction: Action = { [weak self] _ in - self?.welcomeOnboardingCoordinator = nil + withAnimation(.easeIn) { + self?.welcomeOnboardingCoordinator = nil + } } let coordinator = WelcomeOnboardingCoordinator(dismissAction: dismissAction) diff --git a/Tangem/Modules/Welcome/WelcomeCoordinatorView.swift b/Tangem/Modules/Welcome/WelcomeCoordinatorView.swift index c580009a13..3ad176639b 100644 --- a/Tangem/Modules/Welcome/WelcomeCoordinatorView.swift +++ b/Tangem/Modules/Welcome/WelcomeCoordinatorView.swift @@ -20,8 +20,11 @@ struct WelcomeCoordinatorView: CoordinatorView { sheets - if let onboardingCoordinator = coordinator.welcomeOnboardingCoordinator { - WelcomeOnboardingCoordinatorView(coordinator: onboardingCoordinator) + ZStack { // for transition animation + if let onboardingCoordinator = coordinator.welcomeOnboardingCoordinator { + WelcomeOnboardingCoordinatorView(coordinator: onboardingCoordinator) + .transition(.opacity) + } } } } diff --git a/Tangem/Modules/Welcome/WelcomeOnboarding/WelcomeOnboardingView.swift b/Tangem/Modules/Welcome/WelcomeOnboarding/WelcomeOnboardingView.swift index 527de0d7d8..6a38c30395 100644 --- a/Tangem/Modules/Welcome/WelcomeOnboarding/WelcomeOnboardingView.swift +++ b/Tangem/Modules/Welcome/WelcomeOnboarding/WelcomeOnboardingView.swift @@ -24,13 +24,17 @@ struct WelcomeOnboardingView: View { @ViewBuilder private var content: some View { - switch viewModel.viewState { - case .tos(let viewModel): - WelcomeOnboardingTOSView(viewModel: viewModel) - case .pushNotifications(let viewModel): - WelcomeOnboardingPushNotificationsView(viewModel: viewModel) - case .none: - EmptyView() + ZStack { // for transition animation + switch viewModel.viewState { + case .tos(let viewModel): + WelcomeOnboardingTOSView(viewModel: viewModel) + .transition(.opacity.animation(.easeIn)) + case .pushNotifications(let viewModel): + WelcomeOnboardingPushNotificationsView(viewModel: viewModel) + .transition(.opacity.animation(.easeIn)) + case .none: + EmptyView() + } } } }