From 47f1bdefd2c0ecf78658821917ee30adc543900d Mon Sep 17 00:00:00 2001 From: 0xChqrles Date: Mon, 20 May 2024 00:08:11 +0200 Subject: [PATCH 01/36] Introduce SendingView --- .../Contents.json | 0 .../{plus.imageset => Plus.imageset}/plus.svg | 0 .../Contents.json | 0 .../wallet.svg | 0 .../SVG/transfer.imageset/Contents.json | 15 -- .../SVG/transfer.imageset/transfer.svg | 1 - app/App/Components/AmountInput.swift | 79 ----------- app/App/Components/Buttons.swift | 107 ++++++++++---- app/App/Components/FancyAmount.swift | 42 ++++++ app/App/Components/NumPad.swift | 131 ++++++++++++++++++ app/App/Components/ThemedText.swift | 2 +- app/App/Constants/Constants.swift | 16 +++ app/App/Navigation/ContentView.swift | 4 +- .../Navigation/Core/Cards/BalanceView.swift | 2 +- app/App/Navigation/Core/EarnView.swift | 6 +- .../Navigation/Core/{ => Home}/HomeView.swift | 24 +++- .../Navigation/Core/Home/SendingView.swift | 51 +++++++ app/App/Navigation/Core/TransferView.swift | 45 ------ .../{Components => Utils}/Background.swift | 0 app/App/Utils/Container.swift | 18 +++ app/App/Utils/Icon.swift | 17 +++ app/App/Utils/NavigationBar.swift | 37 +++++ app/App/VaultApp.swift | 1 + app/Vault.xcodeproj/project.pbxproj | 47 +++++-- 24 files changed, 456 insertions(+), 189 deletions(-) rename app/App/Assets.xcassets/SVG/{plus.imageset => Plus.imageset}/Contents.json (100%) rename app/App/Assets.xcassets/SVG/{plus.imageset => Plus.imageset}/plus.svg (100%) rename app/App/Assets.xcassets/SVG/{wallet.imageset => Wallet.imageset}/Contents.json (100%) rename app/App/Assets.xcassets/SVG/{wallet.imageset => Wallet.imageset}/wallet.svg (100%) delete mode 100644 app/App/Assets.xcassets/SVG/transfer.imageset/Contents.json delete mode 100644 app/App/Assets.xcassets/SVG/transfer.imageset/transfer.svg delete mode 100644 app/App/Components/AmountInput.swift create mode 100644 app/App/Components/FancyAmount.swift create mode 100644 app/App/Components/NumPad.swift rename app/App/Navigation/Core/{ => Home}/HomeView.swift (90%) create mode 100644 app/App/Navigation/Core/Home/SendingView.swift delete mode 100644 app/App/Navigation/Core/TransferView.swift rename app/App/{Components => Utils}/Background.swift (100%) create mode 100644 app/App/Utils/Container.swift create mode 100644 app/App/Utils/Icon.swift create mode 100644 app/App/Utils/NavigationBar.swift diff --git a/app/App/Assets.xcassets/SVG/plus.imageset/Contents.json b/app/App/Assets.xcassets/SVG/Plus.imageset/Contents.json similarity index 100% rename from app/App/Assets.xcassets/SVG/plus.imageset/Contents.json rename to app/App/Assets.xcassets/SVG/Plus.imageset/Contents.json diff --git a/app/App/Assets.xcassets/SVG/plus.imageset/plus.svg b/app/App/Assets.xcassets/SVG/Plus.imageset/plus.svg similarity index 100% rename from app/App/Assets.xcassets/SVG/plus.imageset/plus.svg rename to app/App/Assets.xcassets/SVG/Plus.imageset/plus.svg diff --git a/app/App/Assets.xcassets/SVG/wallet.imageset/Contents.json b/app/App/Assets.xcassets/SVG/Wallet.imageset/Contents.json similarity index 100% rename from app/App/Assets.xcassets/SVG/wallet.imageset/Contents.json rename to app/App/Assets.xcassets/SVG/Wallet.imageset/Contents.json diff --git a/app/App/Assets.xcassets/SVG/wallet.imageset/wallet.svg b/app/App/Assets.xcassets/SVG/Wallet.imageset/wallet.svg similarity index 100% rename from app/App/Assets.xcassets/SVG/wallet.imageset/wallet.svg rename to app/App/Assets.xcassets/SVG/Wallet.imageset/wallet.svg diff --git a/app/App/Assets.xcassets/SVG/transfer.imageset/Contents.json b/app/App/Assets.xcassets/SVG/transfer.imageset/Contents.json deleted file mode 100644 index 2a2d9f28..00000000 --- a/app/App/Assets.xcassets/SVG/transfer.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "transfer.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/app/App/Assets.xcassets/SVG/transfer.imageset/transfer.svg b/app/App/Assets.xcassets/SVG/transfer.imageset/transfer.svg deleted file mode 100644 index 0cdedf8f..00000000 --- a/app/App/Assets.xcassets/SVG/transfer.imageset/transfer.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/App/Components/AmountInput.swift b/app/App/Components/AmountInput.swift deleted file mode 100644 index eea1f73e..00000000 --- a/app/App/Components/AmountInput.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// AmountInput.swift -// Vault -// -// Created by Charles Lanier on 03/05/2024. -// - -import SwiftUI - -struct AmountInput: View { - - @Binding private var amount: String - @FocusState private var focused: Bool - - private let regex = try! NSRegularExpression(pattern: "^\\d*,?\\d{0,2}$", options: []) - - init(amount: Binding) { - self._amount = amount - } - - var body: some View { - TextField("", text: $amount) - .focused($focused) - .onChange(of: self.amount, initial: false) { (oldValue, newValue) in - - // format input - if let amount = self.formattedAmount(newValue) { - self.amount = amount - } else { - self.amount = oldValue - } - } - .keyboardType(.decimalPad) - .frame(width: 0, height: 0) - .onAppear { - // Automatically focus the TextField when the view appears - DispatchQueue.main.async { - self.focused = true - } - } - - Text("$\(self.amount.isEmpty ? "0" : self.amount)").textTheme(.hero) - } - - private func formattedAmount(_ amount: String) -> String? { - if amount == "," { - return "0," - } else if regex.firstMatch( - in: amount, - options: [], - range: NSRange(location: 0, length: amount.utf8.count) - ) != nil { - // remove useless 0 if needed - return amount.first == "0" && amount.count > 1 && amount[amount.index(amount.startIndex, offsetBy: 1)].isNumber - ? String(amount.dropFirst()) - : amount - } - - return nil - } -} - -#if DEBUG -struct AmountInputPreviews : PreviewProvider { - - @State static var amount: String = "100" - - static var previews: some View { - NavigationStack { - ZStack { - Color.background1.edgesIgnoringSafeArea(.all) - VStack(alignment: .leading, spacing: 16) { - AmountInput(amount: $amount) - } - } - }.preferredColorScheme(.dark) - } -} -#endif diff --git a/app/App/Components/Buttons.swift b/app/App/Components/Buttons.swift index bd7cf033..79cc82cf 100644 --- a/app/App/Components/Buttons.swift +++ b/app/App/Components/Buttons.swift @@ -24,7 +24,7 @@ struct PrimaryButton: View { let text: String let disabled: Bool - let action: (() -> Void) /// use closure for callback + let action: () -> Void init(_ text: String, disabled: Bool = false, action: @escaping () -> Void) { self.text = text @@ -33,7 +33,7 @@ struct PrimaryButton: View { } var body: some View { - Button(action: action) { /// call the closure here + Button(action: action) { Text(text) .textTheme(.button) .frame(maxWidth: .infinity, minHeight: height) @@ -60,7 +60,7 @@ struct SecondaryButton: View { let text: String let disabled: Bool - let action: (() -> Void) /// use closure for callback + let action: () -> Void init(_ text: String, disabled: Bool = false, action: @escaping () -> Void) { self.text = text @@ -69,7 +69,7 @@ struct SecondaryButton: View { } var body: some View { - Button(action: action) { /// call the closure here + Button(action: action) { Text(text) .foregroundStyle(.accent) .textTheme(.button) @@ -82,7 +82,32 @@ struct SecondaryButton: View { } } -// MARK: Capsule button +// MARK: Icon button + +enum IconButtonSize { + case medium + case large + + var buttonSize: CGFloat { + switch self { + case .medium: + return 36 + + case .large: + return 52 + } + } + + var iconSize: CGFloat { + switch self { + case .medium: + return 12 + + case .large: + return 16 + } + } +} struct IconButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { @@ -94,34 +119,48 @@ struct IconButtonStyle: ButtonStyle { } } -struct IconButton: View { - let size: CGFloat = 52 - let iconSize: CGFloat = 16 - - let text: String - let icon: ImageResource - let action: (() -> Void) /// use closure for callback +struct IconButton: View where Icon : View { + let size: IconButtonSize + let icon: Icon + let action: () -> Void - init(_ text: String, iconName: String, action: @escaping () -> Void) { - self.text = text - self.icon = ImageResource(name: iconName, bundle: Bundle.main) + init(size: IconButtonSize = .medium, action: @escaping () -> Void, @ViewBuilder icon: () -> Icon) { + self.icon = icon() + self.size = size self.action = action } var body: some View { VStack(spacing: 10) { - Button(action: action) { /// call the closure here + Button(action: action) { HStack { - Image(self.icon) - .renderingMode(.template) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: self.iconSize, height: self.iconSize) + self.icon + .frame(width: self.size.iconSize, height: self.size.iconSize) .foregroundStyle(.neutral1) } - .frame(width: self.size, height: self.size) + .frame(width: self.size.buttonSize, height: self.size.buttonSize) } .buttonStyle(IconButtonStyle()) + } + } +} + +struct IconButtonWithText: View where Icon : View { + let text: String + let icon: Icon + let action: () -> Void + + init(_ text: String, action: @escaping () -> Void, @ViewBuilder icon: () -> Icon) { + self.text = text + self.icon = icon() + self.action = action + } + + var body: some View { + VStack(spacing: 10) { + IconButton(size: .large, action: self.action) { + self.icon + } Text(self.text).textTheme(.buttonIcon) } @@ -195,8 +234,28 @@ struct NoopButtonStyle: ButtonStyle { Spacer() HStack { - IconButton("Send", iconName: "ArrowUp") {} - IconButton("Add", iconName: "Plus") {} + IconButtonWithText("Send") {} icon: { + Image("ArrowUp") + } + IconButtonWithText("Add") {} icon: { + Image("Plus") + } + } + + Spacer() + + HStack { + IconButton {} icon: { + Image(systemName: "xmark") + .iconify() + .fontWeight(.bold) + } + IconButton {} icon: { + Image(systemName: "chevron.down") + .iconify() + .fontWeight(.bold) + .padding(.top, 4) + } } }.padding(16) } diff --git a/app/App/Components/FancyAmount.swift b/app/App/Components/FancyAmount.swift new file mode 100644 index 00000000..06d1d425 --- /dev/null +++ b/app/App/Components/FancyAmount.swift @@ -0,0 +1,42 @@ +// +// FancyAmount.swift +// Vault +// +// Created by Charles Lanier on 17/05/2024. +// + +import SwiftUI + +struct FancyAmount: View { + @Binding var amount: String + + var body: some View { + let splittedAmount = amount.components(separatedBy: ",") + let shouldDisplayComma = splittedAmount.count > 1 + + HStack(spacing: 4) { + Text("$") + .font(.custom("Sofia Pro", size: 32)) + .textTheme(.hero) + + HStack(alignment: .bottom, spacing: 0) { + Text("\(splittedAmount.first!)\(shouldDisplayComma ? "," : "")") + .font(.custom("Sofia Pro", size: 64)) + .textTheme(.hero) + + Text("\(shouldDisplayComma ? splittedAmount.last! : "")") + .foregroundStyle(.neutral2) + .font(.custom("Sofia Pro", size: 64)) + .textTheme(.hero) + } + } + } +} + +#Preview { + VStack { + FancyAmount(amount: .constant("123,45")) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .defaultBackground() +} diff --git a/app/App/Components/NumPad.swift b/app/App/Components/NumPad.swift new file mode 100644 index 00000000..5a2e1c84 --- /dev/null +++ b/app/App/Components/NumPad.swift @@ -0,0 +1,131 @@ +// +// NumPad.swift +// Vault +// +// Created by Charles Lanier on 17/05/2024. +// + +import SwiftUI + +enum PadTouch: Hashable, Identifiable { + var id: Self { + return self + } + + case char(String) + case backspace + + var label: some View { + Group { + switch self { + case .char(let symbol): + Text(symbol) + .textTheme(.headlineLarge) + + case .backspace: + Image(systemName: "delete.backward") + .font(.system(size: 20)) + .fontWeight(.medium) + .foregroundStyle(.neutral1) + } + } + .frame(maxWidth: .infinity, maxHeight: 64) + } +} + +struct NumPad: View { + + @Binding var amount: String + + private let pad = [ + Container( + [PadTouch.char("1"), PadTouch.char("2"), PadTouch.char("3")] + ), + Container( + [PadTouch.char("4"), PadTouch.char("5"), PadTouch.char("6")] + ), + Container( + [PadTouch.char("7"), PadTouch.char("8"), PadTouch.char("9")] + ), + Container( + [PadTouch.char(","), PadTouch.char("0"), PadTouch.backspace] + ), + ] + + private let regex = try! NSRegularExpression(pattern: "^\\d*,?\\d{0,2}$", options: []) + + var body: some View { + VStack(spacing: 0) { + ForEach(self.pad, id: \.id) { row in + HStack(spacing: 0) { + ForEach(row.elements, id: \.id) { touch in + Button { + let oldValue = self.amount + + switch touch { + case .char(let symbol): + self.amount += symbol + + case .backspace: + self.amount = String(self.amount.dropLast()) + } + + // format input + if let amount = self.formattedAmount(self.amount) { + self.amount = amount + } else { + self.amount = oldValue + } + } label: { + touch.label + } + } + } + } + } + } + + private func formattedAmount(_ amount: String) -> String? { + if amount == "" { + return "0" + } else if regex.firstMatch( + in: amount, + options: [], + range: NSRange(location: 0, length: amount.utf8.count) + ) != nil { + // remove useless 0 if needed + return amount.first == "0" && amount.count > 1 && amount[amount.index(amount.startIndex, offsetBy: 1)].isNumber + ? String(amount.dropFirst()) + : amount + } + + return nil + } +} + +#if DEBUG +struct NumPadPreviews : PreviewProvider { + + struct NumPadContainer: View { + @State private var amount: String = "100" + + var body: some View { + VStack { + Spacer() + + FancyAmount(amount: $amount) + + Spacer() + + NumPad(amount: $amount) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .defaultBackground() + } + } + + static var previews: some View { + NumPadContainer() + } +} +#endif diff --git a/app/App/Components/ThemedText.swift b/app/App/Components/ThemedText.swift index 26a4f71c..8f015852 100644 --- a/app/App/Components/ThemedText.swift +++ b/app/App/Components/ThemedText.swift @@ -32,7 +32,7 @@ struct ThemedTextModifier: ViewModifier { .font(.custom("Sofia Pro", size: 46)) .fontWeight(.medium) .foregroundStyle(.neutral1) - .tracking(1.2) + .tracking(2) case .headlineLarge: content diff --git a/app/App/Constants/Constants.swift b/app/App/Constants/Constants.swift index f4adfd1d..046403ab 100644 --- a/app/App/Constants/Constants.swift +++ b/app/App/Constants/Constants.swift @@ -31,4 +31,20 @@ struct Constants { } return url }() + + // MARK: ICONS + + struct Icons { + static let arrowUp = Self.renderIcon("ArrowUp") + static let arrowDown = Self.renderIcon("ArrowDown") + static let plus = Self.renderIcon("Plus") + + static private func renderIcon(_ name: String) -> any View { + return Image(name) + .renderingMode(.template) + .resizable() + .aspectRatio(contentMode: .fit) + } + } } + diff --git a/app/App/Navigation/ContentView.swift b/app/App/Navigation/ContentView.swift index 2860f02d..1469b877 100644 --- a/app/App/Navigation/ContentView.swift +++ b/app/App/Navigation/ContentView.swift @@ -59,7 +59,7 @@ struct ContentView: View { } .toolbarBackground(.hidden, for: .navigationBar) .environmentObject(settingsModel) - .preferredColorScheme(.dark) +// .preferredColorScheme(.dark) CustomTabbar(selectedTab: $navigationModel.selectedTab) } @@ -70,7 +70,7 @@ struct ContentView: View { } .environmentObject(settingsModel) .environmentObject(registrationModel) - .preferredColorScheme(.dark) +// .preferredColorScheme(.dark) } } } diff --git a/app/App/Navigation/Core/Cards/BalanceView.swift b/app/App/Navigation/Core/Cards/BalanceView.swift index 7f7bc33a..95898482 100644 --- a/app/App/Navigation/Core/Cards/BalanceView.swift +++ b/app/App/Navigation/Core/Cards/BalanceView.swift @@ -12,7 +12,7 @@ struct BalanceView: View { HStack(spacing: 4) { Text("$") .font(.custom("Sofia Pro", size: 32)) - .textTheme(.bodyPrimary) + .textTheme(.hero) HStack(alignment: .bottom, spacing: 0) { Text("456.") diff --git a/app/App/Navigation/Core/EarnView.swift b/app/App/Navigation/Core/EarnView.swift index ade26906..cac8f7a7 100644 --- a/app/App/Navigation/Core/EarnView.swift +++ b/app/App/Navigation/Core/EarnView.swift @@ -13,13 +13,11 @@ struct EarnView: View { Text("Start Earning yield !").textTheme(.headlineLarge) Text("Coming soon").textTheme(.subtitle) } + .frame(maxWidth: .infinity, maxHeight: .infinity) .defaultBackground() } } #Preview { - ZStack { - Color.background1.ignoresSafeArea() - EarnView() - } + EarnView() } diff --git a/app/App/Navigation/Core/HomeView.swift b/app/App/Navigation/Core/Home/HomeView.swift similarity index 90% rename from app/App/Navigation/Core/HomeView.swift rename to app/App/Navigation/Core/Home/HomeView.swift index f4deadc4..ecba49cc 100644 --- a/app/App/Navigation/Core/HomeView.swift +++ b/app/App/Navigation/Core/Home/HomeView.swift @@ -85,6 +85,7 @@ let users: [String: User] = [ struct HomeView: View { @State private var showingAddFundsWebView = false + @State private var showingSendingView = false private var me: User { get { @@ -147,32 +148,41 @@ struct HomeView: View { HStack { Spacer(minLength: 16) - IconButton("Send", iconName: "ArrowUp") { - // TODO: Handle sending + IconButtonWithText("Send") { + self.showingSendingView = true + } icon: { + Image("ArrowUp") } .frame(maxWidth: .infinity) + .fullScreenCover(isPresented: $showingSendingView) { + SendingView() + } Spacer(minLength: 8) - IconButton("Request", iconName: "ArrowDown") { + IconButtonWithText("Request") { // TODO: Handle sending + } icon: { + Image("ArrowDown") } .frame(maxWidth: .infinity) Spacer(minLength: 8) - IconButton("Add funds", iconName: "Plus") { + IconButtonWithText("Add funds") { self.showingAddFundsWebView = true + } icon: { + Image("Plus") } .frame(maxWidth: .infinity) - .fullScreenCover(isPresented: $showingAddFundsWebView) { + .sheet(isPresented: $showingAddFundsWebView) { WebView(url: URL(string: "https://app.fun.xyz")!) } Spacer(minLength: 16) } } - .padding(.bottom, 24) + .padding(.bottom, 16) .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) .listRowBackground(EmptyView()) .listRowSeparator(.hidden) @@ -208,7 +218,7 @@ struct HomeView: View { } header: { Text(formatSectionHeader(for: day).uppercased()) .textTheme(.headlineSmall) - .listRowInsets(EdgeInsets(top: 16, leading: 8, bottom: 8, trailing: 0)) + .listRowInsets(EdgeInsets(top: 32, leading: 8, bottom: 12, trailing: 0)) } .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) .listRowSeparator(.hidden) diff --git a/app/App/Navigation/Core/Home/SendingView.swift b/app/App/Navigation/Core/Home/SendingView.swift new file mode 100644 index 00000000..9cbf31cb --- /dev/null +++ b/app/App/Navigation/Core/Home/SendingView.swift @@ -0,0 +1,51 @@ +// +// SendingView.swift +// Vault +// +// Created by Charles Lanier on 17/05/2024. +// + +import SwiftUI + +struct SendingView: View { + @State private var amount: String = "0" + + @Environment(\.presentationMode) var presentationMode + + var body: some View { + NavigationStack { + VStack { + Spacer() + + FancyAmount(amount: self.$amount) + + Spacer() + + VStack(spacing: 32) { + PrimaryButton("Continue") { + // TODO: logic + } + + NumPad(amount: self.$amount) + } + } + .padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .defaultBackground() + .navigationBarItems( + leading: IconButton { + self.presentationMode.wrappedValue.dismiss() + } icon: { + Image(systemName: "xmark") + .iconify() + .fontWeight(.bold) + } + ) + .removeNavigationBarBorder() + } + } +} + +#Preview { + SendingView() +} diff --git a/app/App/Navigation/Core/TransferView.swift b/app/App/Navigation/Core/TransferView.swift deleted file mode 100644 index dc5330fb..00000000 --- a/app/App/Navigation/Core/TransferView.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// TransferView.swift -// Vault -// -// Created by Charles Lanier on 02/05/2024. -// - -import SwiftUI - -struct TransferView: View { - - @State var amount: String = "" - - @State var rawPhoneNumber: String = "" - - var body: some View { - VStack { - Spacer() - - VStack(alignment: .center, spacing: 64) { - AmountInput(amount: $amount) - - TextInput("phone number", text: $rawPhoneNumber) - .keyboardType(.phonePad) - } - .frame(maxWidth: 250) - - Spacer() - - HStack { - PrimaryButton("Request") {} - PrimaryButton("Send") {} - } - } - .padding(16) - .defaultBackground() - } -} - -#Preview { - ZStack { - Color.background1.edgesIgnoringSafeArea(.all) - TransferView() - } -} diff --git a/app/App/Components/Background.swift b/app/App/Utils/Background.swift similarity index 100% rename from app/App/Components/Background.swift rename to app/App/Utils/Background.swift diff --git a/app/App/Utils/Container.swift b/app/App/Utils/Container.swift new file mode 100644 index 00000000..0d203409 --- /dev/null +++ b/app/App/Utils/Container.swift @@ -0,0 +1,18 @@ +// +// Container.swift +// Vault +// +// Created by Charles Lanier on 19/05/2024. +// + +import Foundation + +struct Container: Identifiable { + let id = UUID() + + var elements: [T] + + init(_ elements: [T]) { + self.elements = elements + } +} diff --git a/app/App/Utils/Icon.swift b/app/App/Utils/Icon.swift new file mode 100644 index 00000000..c51558ae --- /dev/null +++ b/app/App/Utils/Icon.swift @@ -0,0 +1,17 @@ +// +// Icon.swift +// Vault +// +// Created by Charles Lanier on 19/05/2024. +// + +import SwiftUI + +extension Image { + public func iconify() -> some View { + self + .renderingMode(.template) + .resizable() + .aspectRatio(contentMode: .fit) + } +} diff --git a/app/App/Utils/NavigationBar.swift b/app/App/Utils/NavigationBar.swift new file mode 100644 index 00000000..b474bc2d --- /dev/null +++ b/app/App/Utils/NavigationBar.swift @@ -0,0 +1,37 @@ +// +// NavigationBar.swift +// Vault +// +// Created by Charles Lanier on 19/05/2024. +// + +import SwiftUI + +struct NavigationBarModifier: UIViewControllerRepresentable { + + func makeUIViewController(context: Context) -> UIViewController { + let viewController = UIViewController() + + DispatchQueue.main.async { + if let navigationController = viewController.navigationController { + let appearance = UINavigationBarAppearance() + + appearance.configureWithOpaqueBackground() + appearance.backgroundColor = .clear + appearance.shadowColor = .clear + navigationController.navigationBar.standardAppearance = appearance + navigationController.navigationBar.scrollEdgeAppearance = appearance + } + } + + return viewController + } + + func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} +} + +extension View { + func removeNavigationBarBorder() -> some View { + self.background(NavigationBarModifier()) + } +} diff --git a/app/App/VaultApp.swift b/app/App/VaultApp.swift index f4b59661..3322ad3e 100644 --- a/app/App/VaultApp.swift +++ b/app/App/VaultApp.swift @@ -9,6 +9,7 @@ import SwiftUI @main struct VaultApp: App { + var body: some Scene { WindowGroup { ContentView() diff --git a/app/Vault.xcodeproj/project.pbxproj b/app/Vault.xcodeproj/project.pbxproj index 2f1641bf..973a17d8 100644 --- a/app/Vault.xcodeproj/project.pbxproj +++ b/app/Vault.xcodeproj/project.pbxproj @@ -17,6 +17,12 @@ 9C5CFDAE2BC828C9001776E1 /* PhoneNumberModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C5CFDAD2BC828C9001776E1 /* PhoneNumberModel.swift */; }; 9C5CFDB02BC828DE001776E1 /* Locale.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C5CFDAF2BC828DE001776E1 /* Locale.swift */; }; 9C5CFDB22BC82C57001776E1 /* Array+indexed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C5CFDB12BC82C57001776E1 /* Array+indexed.swift */; }; + 9C6259062BF78D120039DE9C /* SendingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C6259052BF78D120039DE9C /* SendingView.swift */; }; + 9C6259082BF79F140039DE9C /* FancyAmount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C6259072BF79F140039DE9C /* FancyAmount.swift */; }; + 9C62590A2BF79F8C0039DE9C /* NumPad.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C6259092BF79F8C0039DE9C /* NumPad.swift */; }; + 9C62590C2BF9FFF60039DE9C /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C62590B2BF9FFF60039DE9C /* Container.swift */; }; + 9C62590E2BFA7D260039DE9C /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C62590D2BFA7D260039DE9C /* Icon.swift */; }; + 9C6259102BFAADB90039DE9C /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C62590F2BFAADB90039DE9C /* NavigationBar.swift */; }; 9C637CD62BB09334005816B4 /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C637CD52BB09334005816B4 /* NotificationsView.swift */; }; 9C637CD92BB09710005816B4 /* NotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C637CD82BB09710005816B4 /* NotificationsManager.swift */; }; 9C637CDB2BB09C4D005816B4 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C637CDA2BB09C4D005816B4 /* Notification.swift */; }; @@ -28,8 +34,6 @@ 9CD1BE962BD589AD0077A60B /* RegistrationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD1BE952BD589AD0077A60B /* RegistrationModel.swift */; }; 9CD1BE982BD7C51A0077A60B /* PhoneNumber+Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD1BE972BD7C51A0077A60B /* PhoneNumber+Parse.swift */; }; 9CD390EB2BE1977E00238FE9 /* HTTPURLReponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD390EA2BE1977E00238FE9 /* HTTPURLReponse.swift */; }; - 9CD390ED2BE3CF5D00238FE9 /* TransferView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD390EC2BE3CF5D00238FE9 /* TransferView.swift */; }; - 9CD390EF2BE5284000238FE9 /* AmountInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD390EE2BE5284000238FE9 /* AmountInput.swift */; }; 9CD390F52BE93A2400238FE9 /* Sofia Pro Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9CD390F42BE93A2400238FE9 /* Sofia Pro Medium.otf */; }; 9CD390F72BEA3D2A00238FE9 /* EarnView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD390F62BEA3D2A00238FE9 /* EarnView.swift */; }; 9CD390FB2BEAB6C600238FE9 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD390FA2BEAB6C600238FE9 /* WebView.swift */; }; @@ -101,6 +105,12 @@ 9C5CFDAD2BC828C9001776E1 /* PhoneNumberModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneNumberModel.swift; sourceTree = ""; }; 9C5CFDAF2BC828DE001776E1 /* Locale.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Locale.swift; sourceTree = ""; }; 9C5CFDB12BC82C57001776E1 /* Array+indexed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+indexed.swift"; sourceTree = ""; }; + 9C6259052BF78D120039DE9C /* SendingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendingView.swift; sourceTree = ""; }; + 9C6259072BF79F140039DE9C /* FancyAmount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyAmount.swift; sourceTree = ""; }; + 9C6259092BF79F8C0039DE9C /* NumPad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumPad.swift; sourceTree = ""; }; + 9C62590B2BF9FFF60039DE9C /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = ""; }; + 9C62590D2BFA7D260039DE9C /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = ""; }; + 9C62590F2BFAADB90039DE9C /* NavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBar.swift; sourceTree = ""; }; 9C637CD52BB09334005816B4 /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = ""; }; 9C637CD82BB09710005816B4 /* NotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsManager.swift; sourceTree = ""; }; 9C637CDA2BB09C4D005816B4 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; @@ -112,8 +122,6 @@ 9CD1BE952BD589AD0077A60B /* RegistrationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationModel.swift; sourceTree = ""; }; 9CD1BE972BD7C51A0077A60B /* PhoneNumber+Parse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PhoneNumber+Parse.swift"; sourceTree = ""; }; 9CD390EA2BE1977E00238FE9 /* HTTPURLReponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPURLReponse.swift; sourceTree = ""; }; - 9CD390EC2BE3CF5D00238FE9 /* TransferView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferView.swift; sourceTree = ""; }; - 9CD390EE2BE5284000238FE9 /* AmountInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmountInput.swift; sourceTree = ""; }; 9CD390F42BE93A2400238FE9 /* Sofia Pro Medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Sofia Pro Medium.otf"; sourceTree = ""; }; 9CD390F62BEA3D2A00238FE9 /* EarnView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EarnView.swift; sourceTree = ""; }; 9CD390FA2BEAB6C600238FE9 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; @@ -186,6 +194,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 9C6259042BF78CF20039DE9C /* Home */ = { + isa = PBXGroup; + children = ( + 9CD778AA2BBAF8BE00BA4677 /* HomeView.swift */, + 9C6259052BF78D120039DE9C /* SendingView.swift */, + ); + path = Home; + sourceTree = ""; + }; 9C637CD72BB096F5005816B4 /* Managers */ = { isa = PBXGroup; children = ( @@ -213,6 +230,10 @@ 9C4F451C2BDEEF0E00D44CBE /* Data+from.swift */, 9CE7A75A2BE12CBC008509FE /* Data+Hex.swift */, 9CD390EA2BE1977E00238FE9 /* HTTPURLReponse.swift */, + 9C62590B2BF9FFF60039DE9C /* Container.swift */, + 9C2E73C42BF3CB86004FFFD1 /* Background.swift */, + 9C62590D2BFA7D260039DE9C /* Icon.swift */, + 9C62590F2BFAADB90039DE9C /* NavigationBar.swift */, ); path = Utils; sourceTree = ""; @@ -235,10 +256,9 @@ 9CD778A92BBAF89F00BA4677 /* Core */ = { isa = PBXGroup; children = ( + 9C6259042BF78CF20039DE9C /* Home */, 9CD778B12BBC38B700BA4677 /* Cards */, - 9CD778AA2BBAF8BE00BA4677 /* HomeView.swift */, 9CD778C32BC1B63800BA4677 /* BudgetView.swift */, - 9CD390EC2BE3CF5D00238FE9 /* TransferView.swift */, 9CD390F62BEA3D2A00238FE9 /* EarnView.swift */, ); path = Core; @@ -367,9 +387,9 @@ 9C5CFDA52BC69446001776E1 /* CountryPickerView.swift */, 9CD1BE892BCD4F5B0077A60B /* OTPInput.swift */, 9CE7A75C2BE15C21008509FE /* SpinnerView.swift */, - 9CD390EE2BE5284000238FE9 /* AmountInput.swift */, 9CD390FA2BEAB6C600238FE9 /* WebView.swift */, - 9C2E73C42BF3CB86004FFFD1 /* Background.swift */, + 9C6259072BF79F140039DE9C /* FancyAmount.swift */, + 9C6259092BF79F8C0039DE9C /* NumPad.swift */, ); path = Components; sourceTree = ""; @@ -527,6 +547,7 @@ files = ( 9CD390EB2BE1977E00238FE9 /* HTTPURLReponse.swift in Sources */, 9C5CFDA62BC69446001776E1 /* CountryPickerView.swift in Sources */, + 9C62590A2BF79F8C0039DE9C /* NumPad.swift in Sources */, 9CD778A82BB2CE7D00BA4677 /* SettingsModel.swift in Sources */, 9CD1BE962BD589AD0077A60B /* RegistrationModel.swift in Sources */, 9CE7A75B2BE12CBC008509FE /* Data+Hex.swift in Sources */, @@ -551,15 +572,18 @@ 9CD778B82BBCB2A100BA4677 /* USDCAmount.swift in Sources */, 9C637CD62BB09334005816B4 /* NotificationsView.swift in Sources */, 9CD778AB2BBAF8BE00BA4677 /* HomeView.swift in Sources */, + 9C6259102BFAADB90039DE9C /* NavigationBar.swift in Sources */, 9CD778C42BC1B63800BA4677 /* BudgetView.swift in Sources */, 9C5CFDB02BC828DE001776E1 /* Locale.swift in Sources */, 9CD7789D2BB1846600BA4677 /* AccessCodeView.swift in Sources */, 9CD778CB2BC3113A00BA4677 /* PhoneRequestView.swift in Sources */, 9CDFD42F2BAB7641000466B9 /* OnboardingView.swift in Sources */, + 9C6259062BF78D120039DE9C /* SendingView.swift in Sources */, 9CD390F72BEA3D2A00238FE9 /* EarnView.swift in Sources */, 9CD778CD2BC3115E00BA4677 /* PhoneValidationView.swift in Sources */, 9C4F451B2BDE999000D44CBE /* String+Error.swift in Sources */, 9CDFD42D2BAB4D1D000466B9 /* WelcomeView.swift in Sources */, + 9C62590C2BF9FFF60039DE9C /* Container.swift in Sources */, 9C637CDB2BB09C4D005816B4 /* Notification.swift in Sources */, 9CDFD4402BAD83E7000466B9 /* ThemedText.swift in Sources */, 9CD1BE8A2BCD4F5B0077A60B /* OTPInput.swift in Sources */, @@ -567,14 +591,14 @@ 9CD778C02BBF1E5C00BA4677 /* EdgeBorder.swift in Sources */, 9CDFD43C2BAC8BE6000466B9 /* FaceIDView.swift in Sources */, 9C4F45192BDE949D00D44CBE /* SecureEnclaveManager.swift in Sources */, - 9CD390EF2BE5284000238FE9 /* AmountInput.swift in Sources */, + 9C62590E2BFA7D260039DE9C /* Icon.swift in Sources */, 9C2E73C52BF3CB86004FFFD1 /* Background.swift in Sources */, 9C5CFDB22BC82C57001776E1 /* Array+indexed.swift in Sources */, 9CD778D42BC4426D00BA4677 /* View+placeholder.swift in Sources */, 9CDFD43A2BAC4561000466B9 /* AskSurnameView.swift in Sources */, 9C2E73C32BF39635004FFFD1 /* BalanceView.swift in Sources */, - 9CD390ED2BE3CF5D00238FE9 /* TransferView.swift in Sources */, 9CD778BA2BBCB89C00BA4677 /* TransferRow.swift in Sources */, + 9C6259082BF79F140039DE9C /* FancyAmount.swift in Sources */, 9C5CFDAE2BC828C9001776E1 /* PhoneNumberModel.swift in Sources */, 9CD1BE982BD7C51A0077A60B /* PhoneNumber+Parse.swift in Sources */, 9CDFD43E2BAD7F12000466B9 /* Shared.swift in Sources */, @@ -697,6 +721,7 @@ INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UIRequiresFullScreen = YES; INFOPLIST_KEY_UIStatusBarStyle = ""; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; @@ -887,6 +912,7 @@ INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UIRequiresFullScreen = YES; INFOPLIST_KEY_UIStatusBarStyle = ""; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; @@ -920,6 +946,7 @@ INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UIRequiresFullScreen = YES; INFOPLIST_KEY_UIStatusBarStyle = ""; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; From f7ca15b4133c70f712cc6d82057d46dcd0c47e0b Mon Sep 17 00:00:00 2001 From: 0xChqrles Date: Thu, 23 May 2024 22:51:47 +0200 Subject: [PATCH 02/36] Add Sending flow --- .../SVG/ArrowDown.imageset/Contents.json | 15 -- .../SVG/ArrowDown.imageset/arrow-down.svg | 1 - .../SVG/ArrowUp.imageset/Contents.json | 15 -- .../SVG/ArrowUp.imageset/arrow-up.svg | 1 - .../SVG/Plus.imageset/plus.svg | 1 - .../Contents.json | 2 +- .../SVG/gear.imageset/gear.svg | 1 + app/App/Components/Buttons.swift | 98 +++++++-- app/App/Components/CountryPickerView.swift | 12 +- app/App/Components/NoAvatar.swift | 33 +++ app/App/Components/NumPad.swift | 2 +- app/App/Components/OTPInput.swift | 2 +- app/App/Components/PhoneInput.swift | 3 +- app/App/Components/ThemedText.swift | 12 +- app/App/Model/ContactsModel.swift | 131 ++++++++++++ app/App/Model/SettingsModel.swift | 33 --- app/App/Navigation/ContentView.swift | 9 +- .../Core/{ => Budget}/BudgetView.swift | 4 +- .../{Cards => Budget}/HistoricalGraph.swift | 0 .../Core/{Cards => Home}/BalanceView.swift | 0 app/App/Navigation/Core/Home/HomeView.swift | 200 ++++++++---------- .../Navigation/Core/Home/SendingView.swift | 51 ----- .../Core/{Cards => Home}/TransferRow.swift | 18 +- .../Navigation/Core/Sending/ContactRow.swift | 53 +++++ .../Core/Sending/NewRecipientView.swift | 54 +++++ .../Core/Sending/SendingAmountView.swift | 67 ++++++ .../Core/Sending/SendingRecipientView.swift | 166 +++++++++++++++ .../Navigation/Core/Sending/SendingView.swift | 20 ++ app/App/Navigation/CustomTabBar.swift | 1 - .../Onboarding/AskSurnameView.swift | 9 +- .../Onboarding/CelebrationView.swift | 5 +- .../Onboarding/NotificationsView.swift | 11 + app/App/Navigation/Onboarding/Shared.swift | 12 +- app/App/Utils/Background.swift | 4 +- app/App/Utils/NavigationBar.swift | 27 ++- app/App/Utils/String+character.swift | 15 ++ app/App/Utils/UIImage.swift | 27 +++ app/Vault-Info.plist | 3 + app/Vault.xcodeproj/project.pbxproj | 63 ++++-- 39 files changed, 862 insertions(+), 319 deletions(-) delete mode 100644 app/App/Assets.xcassets/SVG/ArrowDown.imageset/Contents.json delete mode 100644 app/App/Assets.xcassets/SVG/ArrowDown.imageset/arrow-down.svg delete mode 100644 app/App/Assets.xcassets/SVG/ArrowUp.imageset/Contents.json delete mode 100644 app/App/Assets.xcassets/SVG/ArrowUp.imageset/arrow-up.svg delete mode 100644 app/App/Assets.xcassets/SVG/Plus.imageset/plus.svg rename app/App/Assets.xcassets/SVG/{Plus.imageset => gear.imageset}/Contents.json (86%) create mode 100644 app/App/Assets.xcassets/SVG/gear.imageset/gear.svg create mode 100644 app/App/Components/NoAvatar.swift create mode 100644 app/App/Model/ContactsModel.swift delete mode 100644 app/App/Model/SettingsModel.swift rename app/App/Navigation/Core/{ => Budget}/BudgetView.swift (92%) rename app/App/Navigation/Core/{Cards => Budget}/HistoricalGraph.swift (100%) rename app/App/Navigation/Core/{Cards => Home}/BalanceView.swift (100%) delete mode 100644 app/App/Navigation/Core/Home/SendingView.swift rename app/App/Navigation/Core/{Cards => Home}/TransferRow.swift (74%) create mode 100644 app/App/Navigation/Core/Sending/ContactRow.swift create mode 100644 app/App/Navigation/Core/Sending/NewRecipientView.swift create mode 100644 app/App/Navigation/Core/Sending/SendingAmountView.swift create mode 100644 app/App/Navigation/Core/Sending/SendingRecipientView.swift create mode 100644 app/App/Navigation/Core/Sending/SendingView.swift create mode 100644 app/App/Utils/UIImage.swift diff --git a/app/App/Assets.xcassets/SVG/ArrowDown.imageset/Contents.json b/app/App/Assets.xcassets/SVG/ArrowDown.imageset/Contents.json deleted file mode 100644 index 72fdab2e..00000000 --- a/app/App/Assets.xcassets/SVG/ArrowDown.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "arrow-down.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/app/App/Assets.xcassets/SVG/ArrowDown.imageset/arrow-down.svg b/app/App/Assets.xcassets/SVG/ArrowDown.imageset/arrow-down.svg deleted file mode 100644 index a72f548b..00000000 --- a/app/App/Assets.xcassets/SVG/ArrowDown.imageset/arrow-down.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/App/Assets.xcassets/SVG/ArrowUp.imageset/Contents.json b/app/App/Assets.xcassets/SVG/ArrowUp.imageset/Contents.json deleted file mode 100644 index 2847f54d..00000000 --- a/app/App/Assets.xcassets/SVG/ArrowUp.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "arrow-up.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/app/App/Assets.xcassets/SVG/ArrowUp.imageset/arrow-up.svg b/app/App/Assets.xcassets/SVG/ArrowUp.imageset/arrow-up.svg deleted file mode 100644 index a3ad395d..00000000 --- a/app/App/Assets.xcassets/SVG/ArrowUp.imageset/arrow-up.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/App/Assets.xcassets/SVG/Plus.imageset/plus.svg b/app/App/Assets.xcassets/SVG/Plus.imageset/plus.svg deleted file mode 100644 index f3a79a1b..00000000 --- a/app/App/Assets.xcassets/SVG/Plus.imageset/plus.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/App/Assets.xcassets/SVG/Plus.imageset/Contents.json b/app/App/Assets.xcassets/SVG/gear.imageset/Contents.json similarity index 86% rename from app/App/Assets.xcassets/SVG/Plus.imageset/Contents.json rename to app/App/Assets.xcassets/SVG/gear.imageset/Contents.json index a150fecd..8353f045 100644 --- a/app/App/Assets.xcassets/SVG/Plus.imageset/Contents.json +++ b/app/App/Assets.xcassets/SVG/gear.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "plus.svg", + "filename" : "gear.svg", "idiom" : "universal" } ], diff --git a/app/App/Assets.xcassets/SVG/gear.imageset/gear.svg b/app/App/Assets.xcassets/SVG/gear.imageset/gear.svg new file mode 100644 index 00000000..b0c5b302 --- /dev/null +++ b/app/App/Assets.xcassets/SVG/gear.imageset/gear.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/App/Components/Buttons.swift b/app/App/Components/Buttons.swift index 79cc82cf..1fe33916 100644 --- a/app/App/Components/Buttons.swift +++ b/app/App/Components/Buttons.swift @@ -36,6 +36,7 @@ struct PrimaryButton: View { Button(action: action) { Text(text) .textTheme(.button) + .padding(.top, 2) .frame(maxWidth: .infinity, minHeight: height) } .buttonStyle(PrimaryButtonStyle()) @@ -87,6 +88,7 @@ struct SecondaryButton: View { enum IconButtonSize { case medium case large + case custom(CGFloat, CGFloat) var buttonSize: CGFloat { switch self { @@ -95,6 +97,9 @@ enum IconButtonSize { case .large: return 52 + + case .custom(let buttonSize, _): + return buttonSize } } @@ -105,6 +110,9 @@ enum IconButtonSize { case .large: return 16 + + case .custom(_, let iconSize): + return iconSize } } } @@ -179,23 +187,66 @@ struct TabItemButtonStyle: ButtonStyle { } } -// MARK: Gradient +// MARK: Complex + +enum ComplexButtonStyleMode { + case gradient + case plain +} + +struct ComplexButtonStyle: ButtonStyle { + let mode: ComplexButtonStyleMode + + // TODO: remove duplicated code -struct GradientButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { - configuration.label - .foregroundStyle(.neutral1) - .background( - LinearGradient( - gradient: configuration.isPressed - ? Gradient(colors: [.gradient1B]) - : Constants.gradient1, - startPoint: .topLeading, - endPoint: .bottomTrailing + switch self.mode { + case .gradient: + configuration.label + .foregroundStyle(.neutral1) + .frame(maxWidth: .infinity) + .padding(16) + .background( + LinearGradient( + gradient: configuration.isPressed + ? Gradient(colors: [.gradient1B]) + : Constants.gradient1, + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + .animation(.easeInOut(duration: 0.2), value: configuration.isPressed) ) - .animation(.easeInOut(duration: 0.2), value: configuration.isPressed) - ) - .clipShape(RoundedRectangle(cornerRadius: 16)) + .clipShape(RoundedRectangle(cornerRadius: 16)) + .opacity(configuration.isPressed ? 0.7 : 1) + .animation(.easeOut(duration: 0.1), value: configuration.isPressed) + + case .plain: + configuration.label + .foregroundStyle(.neutral1) + .frame(maxWidth: .infinity) + .padding(16) + .background(.background3) + .clipShape(RoundedRectangle(cornerRadius: 16)) + .opacity(configuration.isPressed ? 0.7 : 1) + .animation(.easeOut(duration: 0.1), value: configuration.isPressed) + } + } +} + +struct ComplexButton