diff --git a/Bitkit/Assets.xcassets/Illustrations/app-icon.imageset/Contents.json b/Bitkit/Assets.xcassets/Illustrations/app-icon-black.imageset/Contents.json similarity index 86% rename from Bitkit/Assets.xcassets/Illustrations/app-icon.imageset/Contents.json rename to Bitkit/Assets.xcassets/Illustrations/app-icon-black.imageset/Contents.json index 955da45d..93240174 100644 --- a/Bitkit/Assets.xcassets/Illustrations/app-icon.imageset/Contents.json +++ b/Bitkit/Assets.xcassets/Illustrations/app-icon-black.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "app-icon.png", + "filename" : "app-icon-black.png", "idiom" : "universal", "scale" : "1x" }, diff --git a/Bitkit/Assets.xcassets/Illustrations/app-icon-black.imageset/app-icon-black.png b/Bitkit/Assets.xcassets/Illustrations/app-icon-black.imageset/app-icon-black.png new file mode 100644 index 00000000..65fc9a8f Binary files /dev/null and b/Bitkit/Assets.xcassets/Illustrations/app-icon-black.imageset/app-icon-black.png differ diff --git a/Bitkit/Assets.xcassets/Illustrations/app-icon-orange.imageset/Contents.json b/Bitkit/Assets.xcassets/Illustrations/app-icon-orange.imageset/Contents.json new file mode 100644 index 00000000..6b698302 --- /dev/null +++ b/Bitkit/Assets.xcassets/Illustrations/app-icon-orange.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "app-icon-orange.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Bitkit/Assets.xcassets/Illustrations/app-icon-orange.imageset/app-icon-orange.png b/Bitkit/Assets.xcassets/Illustrations/app-icon-orange.imageset/app-icon-orange.png new file mode 100644 index 00000000..681149f9 Binary files /dev/null and b/Bitkit/Assets.xcassets/Illustrations/app-icon-orange.imageset/app-icon-orange.png differ diff --git a/Bitkit/Assets.xcassets/Illustrations/app-icon.imageset/app-icon.png b/Bitkit/Assets.xcassets/Illustrations/app-icon.imageset/app-icon.png deleted file mode 100644 index b13fff87..00000000 Binary files a/Bitkit/Assets.xcassets/Illustrations/app-icon.imageset/app-icon.png and /dev/null differ diff --git a/Bitkit/Assets.xcassets/icons/bolt.imageset/bolt.pdf b/Bitkit/Assets.xcassets/icons/bolt.imageset/bolt.pdf index 6109cbaa..8dd13d9c 100644 Binary files a/Bitkit/Assets.xcassets/icons/bolt.imageset/bolt.pdf and b/Bitkit/Assets.xcassets/icons/bolt.imageset/bolt.pdf differ diff --git a/Bitkit/Components/Button/Button.swift b/Bitkit/Components/Button/Button.swift index 4c8dfb50..e3b97d89 100644 --- a/Bitkit/Components/Button/Button.swift +++ b/Bitkit/Components/Button/Button.swift @@ -64,6 +64,7 @@ struct CustomButton: View { let isDisabled: Bool let isLoading: Bool let shouldExpand: Bool + let background: AnyView? let action: (() async -> Void)? let destination: AnyView? @@ -77,7 +78,8 @@ struct CustomButton: View { icon: (any View)? = nil, isDisabled: Bool = false, isLoading: Bool = false, - shouldExpand: Bool = false + shouldExpand: Bool = false, + background: (any View)? = nil ) { self.title = title self.variant = variant @@ -86,6 +88,7 @@ struct CustomButton: View { self.isDisabled = isDisabled self.isLoading = isLoading self.shouldExpand = shouldExpand + self.background = background.map { AnyView($0) } action = nil destination = nil } @@ -99,6 +102,7 @@ struct CustomButton: View { isDisabled: Bool = false, isLoading: Bool = false, shouldExpand: Bool = false, + background: (any View)? = nil, action: @escaping () async -> Void ) { self.title = title @@ -108,6 +112,7 @@ struct CustomButton: View { self.isDisabled = isDisabled self.isLoading = isLoading self.shouldExpand = shouldExpand + self.background = background.map { AnyView($0) } self.action = action destination = nil } @@ -121,6 +126,7 @@ struct CustomButton: View { isDisabled: Bool = false, isLoading: Bool = false, shouldExpand: Bool = false, + background: (any View)? = nil, destination: some View ) { self.title = title @@ -130,6 +136,7 @@ struct CustomButton: View { self.isDisabled = isDisabled self.isLoading = isLoading self.shouldExpand = shouldExpand + self.background = background.map { AnyView($0) } action = nil self.destination = AnyView(destination) } @@ -144,7 +151,8 @@ struct CustomButton: View { isDisabled: isDisabled, isLoading: isLoading, isPressed: isPressed, - shouldExpand: shouldExpand + shouldExpand: shouldExpand, + background: background )) case .secondary: AnyView(SecondaryButtonView( diff --git a/Bitkit/Components/Button/PrimaryButtonView.swift b/Bitkit/Components/Button/PrimaryButtonView.swift index 8317cb84..b8939370 100644 --- a/Bitkit/Components/Button/PrimaryButtonView.swift +++ b/Bitkit/Components/Button/PrimaryButtonView.swift @@ -8,6 +8,7 @@ struct PrimaryButtonView: View { let isLoading: Bool let isPressed: Bool let shouldExpand: Bool + let background: AnyView? var body: some View { HStack(spacing: 8) { @@ -38,9 +39,14 @@ struct PrimaryButtonView: View { } private var backgroundGradient: some View { + if let background { + return background + } + if isLoading { return AnyView(Color.gray6) } + if isDisabled { return AnyView(Color.clear) } diff --git a/Bitkit/Components/CopyAddressCard.swift b/Bitkit/Components/CopyAddressCard.swift index f2aebf7c..cd37873a 100644 --- a/Bitkit/Components/CopyAddressCard.swift +++ b/Bitkit/Components/CopyAddressCard.swift @@ -49,7 +49,10 @@ struct CopyAddressCard: View { onCopy(address: pair.address, index: index) } - ShareLink(item: URL(string: pair.address)!) { + ShareLink( + item: pair.address, + preview: SharePreview(pair.address, image: Image("app-icon-orange")) + ) { CustomButton( title: t("common__share"), size: .small, @@ -77,7 +80,8 @@ struct CopyAddressCard: View { Spacer() } .frame(maxWidth: .infinity, alignment: .leading) - .padding(32) + .padding(.vertical, 32) + .padding(.horizontal, UIScreen.main.isSmall ? 16 : 32) .background(Color.black) .cornerRadius(8) .aspectRatio(1, contentMode: .fit) diff --git a/Bitkit/Components/MoneyStack.swift b/Bitkit/Components/MoneyStack.swift index d1291639..b14147f4 100644 --- a/Bitkit/Components/MoneyStack.swift +++ b/Bitkit/Components/MoneyStack.swift @@ -25,6 +25,7 @@ struct MoneyStack: View { symbol: true, color: .textSecondary ) + .contentTransition(.numericText()) .transition( .move(edge: .bottom) .combined(with: .opacity) @@ -40,6 +41,7 @@ struct MoneyStack: View { prefix: prefix, color: .textPrimary ) + .contentTransition(.numericText()) Spacer() @@ -60,6 +62,7 @@ struct MoneyStack: View { symbol: true, color: .textSecondary ) + .contentTransition(.numericText()) .transition( .move(edge: .bottom) .combined(with: .opacity) @@ -75,6 +78,7 @@ struct MoneyStack: View { prefix: prefix, color: .textPrimary ) + .contentTransition(.numericText()) Spacer() @@ -179,15 +183,20 @@ private extension MoneyStack { #Preview { ScrollView { VStack(alignment: .leading, spacing: 32) { - // With toggle enabled - MoneyStack(sats: 123_456, prefix: "+", showSymbol: false) + // Large amounts to show dramatic transitions + MoneyStack(sats: 1_234_567_890, prefix: "+", showSymbol: false) .environmentObject(MoneyStack.previewCurrencyVM(primaryDisplay: .bitcoin, currency: "USD")) .environmentObject(MoneyStack.previewSettingsVM()) - // With symbol - MoneyStack(sats: 123_456, prefix: "-", showSymbol: true) + // With symbol and different amount + MoneyStack(sats: 987_654_321, prefix: "-", showSymbol: true) .environmentObject(MoneyStack.previewCurrencyVM(primaryDisplay: .fiat, currency: "EUR")) .environmentObject(MoneyStack.previewSettingsVM()) + + // Medium amount with eye icon + MoneyStack(sats: 456_789_123, showEyeIcon: true) + .environmentObject(MoneyStack.previewCurrencyVM(primaryDisplay: .bitcoin, currency: "USD", displayUnit: .classic)) + .environmentObject(MoneyStack.previewSettingsVM(hideBalance: true)) } .frame(maxWidth: .infinity, alignment: .leading) .padding() diff --git a/Bitkit/Components/NotificationPreview.swift b/Bitkit/Components/NotificationPreview.swift index ca95bf8f..b72ecdaf 100644 --- a/Bitkit/Components/NotificationPreview.swift +++ b/Bitkit/Components/NotificationPreview.swift @@ -14,9 +14,10 @@ struct NotificationPreview: View { var body: some View { HStack(alignment: .top, spacing: 8) { - Image("app-icon") + Image("app-icon-black") .resizable() .frame(width: 38, height: 38) + .cornerRadius(9) VStack(alignment: .leading, spacing: 2) { HStack { diff --git a/Bitkit/Components/NumberPad.swift b/Bitkit/Components/NumberPad.swift index 408d59d9..fba37fa4 100644 --- a/Bitkit/Components/NumberPad.swift +++ b/Bitkit/Components/NumberPad.swift @@ -17,7 +17,7 @@ struct NumberPad: View { self.onPress = onPress } - private let buttonHeight: CGFloat = 44 + 34 + private let buttonHeight: CGFloat = UIScreen.main.isSmall ? 65 : 44 + 34 private let gridItems = Array(repeating: GridItem(.flexible(), spacing: 0), count: 3) private let numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] diff --git a/Bitkit/Views/Backup/BackupConfirmMnemonic.swift b/Bitkit/Views/Backup/BackupConfirmMnemonic.swift index 3dd1579c..76b1c087 100644 --- a/Bitkit/Views/Backup/BackupConfirmMnemonic.swift +++ b/Bitkit/Views/Backup/BackupConfirmMnemonic.swift @@ -22,13 +22,12 @@ struct BackupConfirmMnemonic: View { WrappingHStack(spacing: 5) { ForEach(0 ..< shuffledWords.count, id: \.self) { index in - WordButton( - word: shuffledWords[index], - isPressed: pressedIndices.contains(index), - onTap: { - handleWordPress(word: shuffledWords[index], index: index) - } - ) + let word = shuffledWords[index] + let isPressed = pressedIndices.contains(index) + + CustomButton(title: word, size: .small, background: isPressed ? Color.white32 : nil) { + handleWordPress(word: word, index: index) + } } } @@ -118,26 +117,6 @@ struct BackupConfirmMnemonic: View { } } -struct WordButton: View { - let word: String - let isPressed: Bool - let onTap: () -> Void - - var body: some View { - Button(action: onTap) { - Text(word) - .font(.system(size: 15, weight: .semibold)) - .foregroundColor(.textPrimary) - .padding(.horizontal, 12) - .padding(.vertical, 12) - .frame(minWidth: 50) - .background(isPressed ? Color.white32 : Color.white16) - .cornerRadius(54) - } - .buttonStyle(PlainButtonStyle()) - } -} - struct ConfirmWordView: View { let number: Int let word: String diff --git a/Bitkit/Views/Backup/BackupMetadata.swift b/Bitkit/Views/Backup/BackupMetadata.swift index f8a544ff..c8800533 100644 --- a/Bitkit/Views/Backup/BackupMetadata.swift +++ b/Bitkit/Views/Backup/BackupMetadata.swift @@ -21,8 +21,13 @@ struct BackupMetadata: View { Spacer() // TODO: Add actual last backup time - BodySText(t("security__mnemonic_latest_backup", variables: ["time": "12/06/2025 12:00"])) - .padding(.bottom, 16) + BodySText( + tTodo("Latest full backup: {time}", variables: ["time": "12/06/2025 12:00"]), + textColor: .textPrimary, + accentColor: .textPrimary, + accentFont: Fonts.bold + ) + .padding(.bottom, 16) CustomButton(title: t("common__ok")) { sheets.hideSheet() diff --git a/Bitkit/Views/Backup/BackupMnemonic.swift b/Bitkit/Views/Backup/BackupMnemonic.swift index 4d346965..aa8c76ed 100644 --- a/Bitkit/Views/Backup/BackupMnemonic.swift +++ b/Bitkit/Views/Backup/BackupMnemonic.swift @@ -7,12 +7,24 @@ struct BackupMnemonicView: View { @State private var passphrase: String = "" @State private var showMnemonic: Bool = false + private var text: String { + showMnemonic + ? t("security__mnemonic_write", variables: ["length": "\(mnemonic.count)"]) + : t("security__mnemonic_use") + } + + private var note: String { + showMnemonic + ? "Bitkit cannot access your funds and cannot help recover them if you lose your recovery phrase. Keep it safe!" + : "Make sure no one can see your screen. Never share your recovery phrase with anyone, as it may result in loss of funds." + } + var body: some View { VStack(alignment: .leading, spacing: 0) { SheetHeader(title: t("security__mnemonic_your")) VStack(spacing: 0) { - BodyMText(t("security__mnemonic_write", variables: ["length": "\(mnemonic.count)"])) + BodyMText(text) .frame(maxWidth: .infinity, alignment: .leading) .padding(.bottom, 16) @@ -35,25 +47,18 @@ struct BackupMnemonicView: View { .frame(maxWidth: .infinity, alignment: .leading) } .padding(32) - .background(Color.white10) + .background(Color.gray6) .blur(radius: showMnemonic ? 0 : 5) .privacySensitive() if !showMnemonic { - Button(action: { + CustomButton( + title: t("security__mnemonic_reveal"), + icon: Image("eye").resizable().frame(width: 16, height: 16) + ) { showMnemonic = true - }) { - BodySSBText(t("security__mnemonic_reveal")) - .frame(width: 154, height: 56) - .background(Color.black50) - .cornerRadius(64) } - .shadow( - color: Color.black.opacity(0.25), - radius: 50, - x: 0, - y: 25 - ) + .frame(maxWidth: 180) } } .cornerRadius(16) @@ -67,15 +72,12 @@ struct BackupMnemonicView: View { } } - BodySText(t("security__mnemonic_never_share"), accentColor: .brandAccent) + BodySText(tTodo(note), textColor: .brandAccent, accentFont: Fonts.bold) Spacer() HStack(alignment: .center, spacing: 16) { - CustomButton( - title: t("common__continue"), - isDisabled: !showMnemonic - ) { + CustomButton(title: t("common__continue"), isDisabled: !showMnemonic) { let route = passphrase.isEmpty ? BackupRoute.confirmMnemonic(mnemonic: mnemonic, passphrase: passphrase) @@ -83,7 +85,6 @@ struct BackupMnemonicView: View { navigationPath.append(route) } } - .padding(.top, 32) } .padding(.horizontal, 16) } diff --git a/Bitkit/Views/Backup/BackupPassphrase.swift b/Bitkit/Views/Backup/BackupPassphrase.swift index 253eb92f..ecebb682 100644 --- a/Bitkit/Views/Backup/BackupPassphrase.swift +++ b/Bitkit/Views/Backup/BackupPassphrase.swift @@ -25,21 +25,23 @@ struct BackupPassphrase: View { } .padding(32) .frame(maxHeight: .infinity) - .background(Color.white10) + .background(Color.gray6) .cornerRadius(16) .padding(.top, 16) .padding(.bottom, 32) .privacySensitive() .frame(maxWidth: .infinity) - BodySText(t("security__pass_never_share"), accentColor: .brandAccent) + BodySText( + tTodo("Never share your passphrase with anyone, as it may result in loss of funds. Keep it secret!"), + accentColor: .brandAccent, + accentFont: Fonts.bold + ) Spacer() HStack(alignment: .center, spacing: 16) { - CustomButton( - title: t("common__continue") - ) { + CustomButton(title: t("common__continue")) { navigationPath.append(.confirmMnemonic(mnemonic: mnemonic, passphrase: passphrase)) } } diff --git a/Bitkit/Views/Settings/Advanced/CoinSelectionSettingsView.swift b/Bitkit/Views/Settings/Advanced/CoinSelectionSettingsView.swift index 9b3e00e7..8ca39f7f 100644 --- a/Bitkit/Views/Settings/Advanced/CoinSelectionSettingsView.swift +++ b/Bitkit/Views/Settings/Advanced/CoinSelectionSettingsView.swift @@ -67,10 +67,12 @@ struct CoinSelectionMethodOption: View { Spacer() if isSelected { Image("checkmark") + .resizable() + .frame(width: 32, height: 32) .foregroundColor(.brandAccent) } } - .padding(.vertical, 8) + .frame(height: 51) .contentShape(Rectangle()) } .buttonStyle(PlainButtonStyle()) @@ -84,26 +86,25 @@ struct CoinSelectionAlgorithmOption: View { var body: some View { Button(action: onTap) { - VStack(alignment: .leading, spacing: 8) { + VStack(alignment: .leading, spacing: 0) { HStack { BodyMText(algorithm.localizedTitle, textColor: .textPrimary) Spacer() if isSelected { Image("checkmark") + .resizable() + .frame(width: 32, height: 32) .foregroundColor(.brandAccent) - .frame(width: 23, height: 16) } } + .frame(height: 51) - Divider() + BodySText(algorithm.localizedDescription) + .multilineTextAlignment(.leading) + .padding(.bottom, 16) - BodySText( - algorithm.localizedDescription, - textColor: .textSecondary - ) - .multilineTextAlignment(.leading) + Divider() } - .padding(.vertical, 12) .contentShape(Rectangle()) } .buttonStyle(PlainButtonStyle()) @@ -122,19 +123,12 @@ struct CoinSelectionSettingsView: View { VStack(spacing: 0) { // COIN SELECTION METHOD Section VStack(alignment: .leading, spacing: 0) { - HStack { - BodyMText( - t("settings__adv__cs_method"), - textColor: .textSecondary - ) + CaptionMText(t("settings__adv__cs_method")) .padding(.bottom, 8) - Spacer() - } - VStack(spacing: 0) { ForEach(CoinSelectionMethod.allCases, id: \.self) { method in - VStack { + VStack(spacing: 0) { CoinSelectionMethodOption( method: method, isSelected: settingsViewModel.coinSelectionMethod == method @@ -153,17 +147,10 @@ struct CoinSelectionSettingsView: View { // AUTOPILOT MODE Section (only show if Autopilot is selected) if settingsViewModel.coinSelectionMethod == .autopilot { VStack(alignment: .leading, spacing: 0) { - HStack { - BodyMText( - t("settings__adv__cs_auto_mode"), - textColor: .textSecondary - ) + CaptionMText(t("settings__adv__cs_auto_mode")) .padding(.top, 24) .padding(.bottom, 8) - Spacer() - } - VStack(spacing: 0) { ForEach(CoinSelectionAlgorithm.supportedAlgorithms, id: \.self) { algorithm in VStack { diff --git a/Bitkit/Views/Settings/General/LocalCurrencySettingsView.swift b/Bitkit/Views/Settings/General/LocalCurrencySettingsView.swift index 3307dcff..7854bac3 100644 --- a/Bitkit/Views/Settings/General/LocalCurrencySettingsView.swift +++ b/Bitkit/Views/Settings/General/LocalCurrencySettingsView.swift @@ -42,12 +42,30 @@ struct LocalCurrencySettingsView: View { var body: some View { VStack(alignment: .leading, spacing: 0) { NavigationBar(title: t("settings__general__currency_local_title")) + .padding(.bottom, 16) + + // Custom search bar + HStack(spacing: 0) { + Image("magnifying-glass") + .resizable() + .frame(width: 24, height: 24) + .foregroundColor(!searchText.isEmpty ? .brandAccent : .white64) + TextField(t("common__search"), text: $searchText, backgroundColor: .clear, font: .custom(Fonts.regular, size: 17)) + .frame(maxWidth: .infinity) + .offset(x: -5) + } + .frame(height: 48) + .padding(.horizontal, 16) + .background(Color.gray6) + .cornerRadius(32) + .padding(.bottom, 16) ScrollView(showsIndicators: false) { if !availableMostUsed.isEmpty { - VStack(alignment: .leading, spacing: 8) { - CaptionText(t("settings__general__currency_most_used").uppercased()) - .padding(.vertical, 16) + VStack(alignment: .leading, spacing: 0) { + CaptionMText(t("settings__general__currency_most_used")) + .padding(.top, 16) + .padding(.bottom, 8) .frame(maxWidth: .infinity, alignment: .leading) ForEach(availableMostUsed, id: \.quote) { rate in @@ -56,22 +74,25 @@ struct LocalCurrencySettingsView: View { } } - VStack(alignment: .leading, spacing: 8) { - CaptionText(t("settings__general__currency_other").uppercased()) - .padding(.vertical, 16) + VStack(alignment: .leading, spacing: 0) { + CaptionMText(t("settings__general__currency_other")) + .padding(.top, 24) + .padding(.bottom, 8) .frame(maxWidth: .infinity, alignment: .leading) ForEach(otherCurrencies, id: \.quote) { rate in currencyRow(rate) } } + + CaptionText(t("settings__general__currency_footer")) + .padding(.top, 16) + .frame(maxWidth: .infinity, alignment: .leading) } } .navigationBarHidden(true) .padding(.horizontal, 16) .bottomSafeAreaPadding() - // TODO: Fix search - .searchable(text: $searchText, prompt: t("common__search")) } } diff --git a/Bitkit/Views/Settings/General/TagSettingsView.swift b/Bitkit/Views/Settings/General/TagSettingsView.swift index 2750d563..dd375a96 100644 --- a/Bitkit/Views/Settings/General/TagSettingsView.swift +++ b/Bitkit/Views/Settings/General/TagSettingsView.swift @@ -10,8 +10,7 @@ struct TagSettingsView: View { ScrollView(showsIndicators: false) { VStack(alignment: .leading, spacing: 0) { - CaptionText(t("settings__general__tags_previously")) - .textCase(.uppercase) + CaptionMText(t("settings__general__tags_previously")) .padding(.top, 24) .padding(.bottom, 16) .frame(maxWidth: .infinity, alignment: .leading) diff --git a/Bitkit/Views/Settings/MainSettings.swift b/Bitkit/Views/Settings/MainSettings.swift index d9b59ad1..1d15fba2 100644 --- a/Bitkit/Views/Settings/MainSettings.swift +++ b/Bitkit/Views/Settings/MainSettings.swift @@ -1,11 +1,7 @@ import SwiftUI struct MainSettings: View { - @EnvironmentObject var app: AppViewModel - @EnvironmentObject var activity: ActivityListViewModel - @EnvironmentObject var navigation: NavigationViewModel - @EnvironmentObject var wallet: WalletViewModel - @EnvironmentObject var widgets: WidgetsViewModel + @EnvironmentObject private var app: AppViewModel @AppStorage("showDevSettings") private var showDevSettings = Env.isDebug @State private var cogTapCount = 0 @@ -69,7 +65,6 @@ struct MainSettings: View { } Spacer() - .frame(minHeight: 32) Image("cog") .resizable() @@ -93,7 +88,6 @@ struct MainSettings: View { } Spacer() - .frame(minHeight: 32) } .frame(minHeight: geometry.size.height) } diff --git a/Bitkit/Views/Settings/Quickpay/QuickpaySettings.swift b/Bitkit/Views/Settings/Quickpay/QuickpaySettings.swift index 47427071..a375252b 100644 --- a/Bitkit/Views/Settings/Quickpay/QuickpaySettings.swift +++ b/Bitkit/Views/Settings/Quickpay/QuickpaySettings.swift @@ -1,15 +1,14 @@ import SwiftUI struct QuickpaySettings: View { - @EnvironmentObject var app: AppViewModel - @EnvironmentObject var navigation: NavigationViewModel - @EnvironmentObject var settings: SettingsViewModel + @EnvironmentObject private var settings: SettingsViewModel private let sliderSteps: [Double] = [1, 5, 10, 20, 50] var body: some View { VStack(alignment: .leading, spacing: 0) { NavigationBar(title: t("settings__quickpay__nav_title")) + .padding(.horizontal, 16) GeometryReader { geometry in ScrollView(showsIndicators: false) { @@ -25,10 +24,7 @@ struct QuickpaySettings: View { .padding(.top, 16) VStack(alignment: .leading, spacing: 16) { - CaptionText( - t("settings__quickpay__settings__label").uppercased() - ) - + CaptionMText(t("settings__quickpay__settings__label")) CustomSlider(value: $settings.quickpayAmount, steps: sliderSteps) } .padding(.top, 32) @@ -45,19 +41,16 @@ struct QuickpaySettings: View { } .frame(maxWidth: .infinity) .padding(.horizontal, 16) - .padding(.vertical, 32) + // .padding(.vertical, 32) - BodySText( - t("settings__quickpay__settings__note"), - textColor: .textSecondary - ) + BodySText(t("settings__quickpay__settings__note")) } .frame(minHeight: geometry.size.height) + .padding(.horizontal, 16) .bottomSafeAreaPadding() } } } .navigationBarHidden(true) - .padding(.horizontal, 16) } } diff --git a/Bitkit/Views/Settings/Support/ReportIssue.swift b/Bitkit/Views/Settings/Support/ReportIssue.swift index 8fe6458a..c0ee7c67 100644 --- a/Bitkit/Views/Settings/Support/ReportIssue.swift +++ b/Bitkit/Views/Settings/Support/ReportIssue.swift @@ -105,7 +105,7 @@ struct ReportIssue: View { VStack(alignment: .leading, spacing: 26) { VStack(alignment: .leading, spacing: 8) { - CaptionText(t("settings__support__label_address").uppercased()) + CaptionMText(t("settings__support__label_address")) TextField( t("settings__support__placeholder_address"), @@ -117,10 +117,7 @@ struct ReportIssue: View { } VStack(alignment: .leading, spacing: 8) { - CaptionText( - t("settings__support__label_message").uppercased(), - textColor: .textSecondary - ) + CaptionMText(t("settings__support__label_message")) ZStack(alignment: .topLeading) { if message.isEmpty { diff --git a/Bitkit/Views/Settings/TransactionSpeed/TransactionSpeedSettingsView.swift b/Bitkit/Views/Settings/TransactionSpeed/TransactionSpeedSettingsView.swift index 2ec00864..b5a4d8d9 100644 --- a/Bitkit/Views/Settings/TransactionSpeed/TransactionSpeedSettingsView.swift +++ b/Bitkit/Views/Settings/TransactionSpeed/TransactionSpeedSettingsView.swift @@ -17,7 +17,7 @@ struct TransactionSpeedSettingsRow: View { var body: some View { Button(action: onSelect) { - HStack { + HStack(spacing: 0) { Image(speed.iconName) .resizable() .scaledToFit() diff --git a/Bitkit/Views/Shop/ShopDiscover.swift b/Bitkit/Views/Shop/ShopDiscover.swift index 812874e8..cd3a4fa1 100644 --- a/Bitkit/Views/Shop/ShopDiscover.swift +++ b/Bitkit/Views/Shop/ShopDiscover.swift @@ -111,8 +111,7 @@ struct ShopDiscover: View { .padding(.bottom, 16) VStack { - CaptionText(t("other__shop__discover__label")) - .textCase(.uppercase) + CaptionMText(t("other__shop__discover__label")) .frame(maxWidth: .infinity, alignment: .leading) } .frame(height: 50) diff --git a/Bitkit/Views/Transfer/FundManualAmountView.swift b/Bitkit/Views/Transfer/FundManualAmountView.swift index 2993d34c..9d41494f 100644 --- a/Bitkit/Views/Transfer/FundManualAmountView.swift +++ b/Bitkit/Views/Transfer/FundManualAmountView.swift @@ -20,6 +20,7 @@ struct FundManualAmountView: View { VStack(alignment: .leading, spacing: 0) { DisplayText(t("lightning__external_amount__title"), accentColor: .purpleAccent) + .fixedSize(horizontal: false, vertical: true) NumberPadTextField(viewModel: amountViewModel, showConversion: false) .onTapGesture { diff --git a/Bitkit/Views/Transfer/FundManualSuccessView.swift b/Bitkit/Views/Transfer/FundManualSuccessView.swift index 5abb9e21..62043a14 100644 --- a/Bitkit/Views/Transfer/FundManualSuccessView.swift +++ b/Bitkit/Views/Transfer/FundManualSuccessView.swift @@ -17,6 +17,7 @@ struct FundManualSuccessView: View { t("lightning__external_success__title"), accentColor: .purpleAccent ) + .fixedSize(horizontal: false, vertical: true) BodyMText( t("lightning__external_success__text"), diff --git a/Bitkit/Views/Transfer/SavingsConfirmView.swift b/Bitkit/Views/Transfer/SavingsConfirmView.swift index 3d992d9c..f37260ac 100644 --- a/Bitkit/Views/Transfer/SavingsConfirmView.swift +++ b/Bitkit/Views/Transfer/SavingsConfirmView.swift @@ -40,6 +40,7 @@ struct SavingsConfirmView: View { .padding(.bottom, 16) DisplayText(t("lightning__transfer__confirm"), accentColor: .brandAccent) + .fixedSize(horizontal: false, vertical: true) CaptionMText(t("lightning__savings_confirm__label")) .padding(.top, 32) diff --git a/Bitkit/Views/Transfer/SettingUpView.swift b/Bitkit/Views/Transfer/SettingUpView.swift index d02fe7ac..9249de87 100644 --- a/Bitkit/Views/Transfer/SettingUpView.swift +++ b/Bitkit/Views/Transfer/SettingUpView.swift @@ -1,6 +1,61 @@ import BitkitCore import SwiftUI +struct SettingUpLoadingView: View { + @State private var outerRotation: Double = 0 + @State private var innerRotation: Double = 0 + @State private var transferRotation: Double = 0 + + var size: (container: CGFloat, image: CGFloat, inner: CGFloat) { + let container: CGFloat = UIScreen.main.isSmall ? 200 : 320 + let image = container * 0.8 + let inner = container * 0.7 + + return (container: container, image: image, inner: inner) + } + + var body: some View { + ZStack(alignment: .center) { + // Outer ellipse + Image("ellipse-outer-purple") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: size.container, height: size.container) + .rotationEffect(.degrees(outerRotation)) + + // Inner ellipse + Image("ellipse-inner-purple") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: size.inner, height: size.inner) + .rotationEffect(.degrees(innerRotation)) + + // Transfer image + Image("transfer-figure") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: size.image, height: size.image) + .rotationEffect(.degrees(transferRotation)) + } + .frame(width: size.container, height: size.container) + .clipped() + .frame(maxWidth: .infinity) + .onAppear { + withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) { + outerRotation = -90 + } + + withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) { + innerRotation = 120 + } + + withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) { + transferRotation = 90 + } + } + } +} + struct ProgressSteps: View { let steps: [String] let currentStep: Int @@ -68,9 +123,6 @@ struct SettingUpView: View { @EnvironmentObject var navigation: NavigationViewModel @EnvironmentObject var transfer: TransferViewModel - @State private var outerRotation: Double = 0 - @State private var innerRotation: Double = 0 - @State private var transferRotation: Double = 0 // Keep in state so we don't get a new random text on each render @State private var randomOkText: String = localizedRandom("common__ok_random") @@ -116,44 +168,7 @@ struct SettingUpView: View { Spacer() if isTransferring { - ZStack(alignment: .center) { - // Outer ellipse - Image("ellipse-outer-purple") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 311, height: 311) - .rotationEffect(.degrees(outerRotation)) - - // Inner ellipse - Image("ellipse-inner-purple") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 207, height: 207) - .rotationEffect(.degrees(innerRotation)) - - // Transfer image - Image("transfer-figure") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 256, height: 256) - .rotationEffect(.degrees(transferRotation)) - } - .frame(width: 320, height: 320) - .clipped() - .frame(maxWidth: .infinity) - .onAppear { - withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) { - outerRotation = -90 - } - - withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) { - innerRotation = 120 - } - - withAnimation(.easeInOut(duration: 3).repeatForever(autoreverses: true)) { - transferRotation = 90 - } - } + SettingUpLoadingView() } else { Image("check") .resizable() @@ -167,7 +182,7 @@ struct SettingUpView: View { if isTransferring { ProgressSteps(steps: steps, currentStep: transfer.lightningSetupStep) - .padding(.bottom, 32) + .padding(.bottom, 16) } CustomButton(title: buttonTitle) { diff --git a/Bitkit/Views/Transfer/SpendingAdvancedView.swift b/Bitkit/Views/Transfer/SpendingAdvancedView.swift index eef8ed68..5e0bdbbe 100644 --- a/Bitkit/Views/Transfer/SpendingAdvancedView.swift +++ b/Bitkit/Views/Transfer/SpendingAdvancedView.swift @@ -31,6 +31,7 @@ struct SpendingAdvancedView: View { VStack(alignment: .leading, spacing: 0) { DisplayText(t("lightning__spending_advanced__title"), accentColor: .purpleAccent) + .fixedSize(horizontal: false, vertical: true) NumberPadTextField(viewModel: amountViewModel, showConversion: false) .onTapGesture { diff --git a/Bitkit/Views/Transfer/SpendingAmount.swift b/Bitkit/Views/Transfer/SpendingAmount.swift index dca230d2..7397a900 100644 --- a/Bitkit/Views/Transfer/SpendingAmount.swift +++ b/Bitkit/Views/Transfer/SpendingAmount.swift @@ -32,6 +32,7 @@ struct SpendingAmount: View { .padding(.bottom, 16) DisplayText(t("lightning__spending_amount__title"), accentColor: .purpleAccent) + .fixedSize(horizontal: false, vertical: true) NumberPadTextField(viewModel: amountViewModel, showConversion: false) .onTapGesture { diff --git a/Bitkit/Views/Transfer/SpendingConfirm.swift b/Bitkit/Views/Transfer/SpendingConfirm.swift index 8e45e7bc..9a752d33 100644 --- a/Bitkit/Views/Transfer/SpendingConfirm.swift +++ b/Bitkit/Views/Transfer/SpendingConfirm.swift @@ -25,7 +25,7 @@ struct SpendingConfirm: View { var body: some View { VStack(alignment: .leading, spacing: 0) { NavigationBar(title: t("lightning__transfer__nav_title")) - .padding(.bottom, 32) + .padding(.bottom, 16) DisplayText(t("lightning__transfer__confirm"), accentColor: .purpleAccent) diff --git a/Bitkit/Views/Wallets/Activity/ActivityItemView.swift b/Bitkit/Views/Wallets/Activity/ActivityItemView.swift index 6018085f..f691a586 100644 --- a/Bitkit/Views/Wallets/Activity/ActivityItemView.swift +++ b/Bitkit/Views/Wallets/Activity/ActivityItemView.swift @@ -101,28 +101,33 @@ struct ActivityItemView: View { } var body: some View { - VStack(alignment: .leading, spacing: 16) { + VStack(alignment: .leading, spacing: 0) { NavigationBar(title: navigationTitle) + .padding(.bottom, 16) - HStack(alignment: .bottom) { - MoneyStack(sats: amount, prefix: amountPrefix, showSymbol: false) - Spacer() - ActivityIcon(activity: viewModel.activity, size: 48) - } - .padding(.bottom, 16) + ScrollView(showsIndicators: false) { + VStack(spacing: 16) { + HStack(alignment: .bottom) { + MoneyStack(sats: amount, prefix: amountPrefix, showSymbol: false) + Spacer() + ActivityIcon(activity: viewModel.activity, size: 48) + } + .padding(.bottom, 16) - statusSection - timestampSection - feeSection - tagsSection - note - buttons + statusSection + timestampSection + feeSection + tagsSection + note + buttons - Spacer() + Spacer() + } + .bottomSafeAreaPadding() + } } .navigationBarHidden(true) .padding(.horizontal, 16) - .bottomSafeAreaPadding() .onChange(of: sheets.addTagSheetItem) { item in if item == nil { // Add tag sheet was closed, reload tags in case they were modified @@ -158,6 +163,7 @@ struct ActivityItemView: View { BodySSBText(t("wallet__activity_pending"), textColor: .purpleAccent) case .succeeded: Image("bolt") + .resizable() .foregroundColor(.purpleAccent) .frame(width: 16, height: 16) BodySSBText(t("wallet__activity_successful"), textColor: .purpleAccent) diff --git a/Bitkit/Views/Wallets/Activity/ActivityRowLightning.swift b/Bitkit/Views/Wallets/Activity/ActivityRowLightning.swift index 929f118e..c1f9e0f3 100644 --- a/Bitkit/Views/Wallets/Activity/ActivityRowLightning.swift +++ b/Bitkit/Views/Wallets/Activity/ActivityRowLightning.swift @@ -47,6 +47,7 @@ struct ActivityRowLightning: View { VStack(alignment: .leading, spacing: 2) { ActivityStatus(txType: item.txType, status: item.status) CaptionBText(item.message.isEmpty ? formattedTime : item.message) + .lineLimit(1) } Spacer() diff --git a/Bitkit/Views/Wallets/Receive/ReceiveQr.swift b/Bitkit/Views/Wallets/Receive/ReceiveQr.swift index 67728b31..ba5d5119 100644 --- a/Bitkit/Views/Wallets/Receive/ReceiveQr.swift +++ b/Bitkit/Views/Wallets/Receive/ReceiveQr.swift @@ -86,11 +86,14 @@ struct ReceiveQr: View { Spacer() - VStack(spacing: 0) { + Group { if showingCjitOnboarding { CustomButton( title: t("wallet__receive_spending"), - icon: Image("bolt").foregroundColor(.purpleAccent), + icon: Image("bolt") + .resizable() + .frame(width: 16, height: 16) + .foregroundColor(.purpleAccent), isDisabled: wallet.nodeLifecycleState != .running ) { navigationPath.append(.cjitAmount) @@ -207,11 +210,13 @@ struct ReceiveQr: View { .cornerRadius(8) .aspectRatio(1, contentMode: .fit) .overlay(alignment: .bottomLeading) { - Image("arrow-cjit") - .resizable() - .scaledToFit() - .frame(height: 210) - .offset(x: 70, y: 110) + if !UIScreen.main.isSmall { + Image("arrow-cjit") + .resizable() + .scaledToFit() + .frame(height: 210) + .offset(x: 70, y: 110) + } } } diff --git a/Bitkit/Views/Wallets/Send/SendConfirmationView.swift b/Bitkit/Views/Wallets/Send/SendConfirmationView.swift index 4ffe4f91..9f9bb37c 100644 --- a/Bitkit/Views/Wallets/Send/SendConfirmationView.swift +++ b/Bitkit/Views/Wallets/Send/SendConfirmationView.swift @@ -521,7 +521,7 @@ struct SendConfirmationView: View { BodySSBText(description) } .frame(maxWidth: .infinity, alignment: .leading) - .padding(.bottom, 16) + .padding(.vertical, 16) Divider() } diff --git a/Bitkit/Views/Wallets/Send/SendEnterManuallyView.swift b/Bitkit/Views/Wallets/Send/SendEnterManuallyView.swift index e7bf875d..9e36958f 100644 --- a/Bitkit/Views/Wallets/Send/SendEnterManuallyView.swift +++ b/Bitkit/Views/Wallets/Send/SendEnterManuallyView.swift @@ -12,7 +12,7 @@ struct SendEnterManuallyView: View { VStack { SheetHeader(title: t("wallet__send_bitcoin"), showBackButton: true) - CaptionText(t("wallet__send_to").uppercased()) + CaptionMText(t("wallet__send_to")) .frame(maxWidth: .infinity, alignment: .leading) ZStack(alignment: .topLeading) { diff --git a/Bitkit/Views/Widgets/WidgetDetailView.swift b/Bitkit/Views/Widgets/WidgetDetailView.swift index 10ce4e17..409b1182 100644 --- a/Bitkit/Views/Widgets/WidgetDetailView.swift +++ b/Bitkit/Views/Widgets/WidgetDetailView.swift @@ -122,8 +122,7 @@ struct WidgetDetailView: View { Spacer() VStack(alignment: .leading, spacing: 0) { - CaptionText(t("common__preview")) - .textCase(.uppercase) + CaptionMText(t("common__preview")) .padding(.top, 16) .padding(.bottom, 16)