initial version
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import SwiftUI
|
||||
|
||||
struct AccountEditorView: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@EnvironmentObject private var accountStore: AccountStore
|
||||
let account: Account?
|
||||
|
||||
@State private var name = ""
|
||||
@State private var currencyCode = AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currency
|
||||
@State private var inputMode: InputMode = .simple
|
||||
@State private var notificationFrequency: NotificationFrequency = .monthly
|
||||
@State private var customFrequencyMonths = 1
|
||||
|
||||
private let accountRepository = AccountRepository()
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
Section {
|
||||
TextField("Account name", text: $name)
|
||||
Picker("Currency", selection: $currencyCode) {
|
||||
ForEach(CurrencyPicker.commonCodes, id: \.self) { code in
|
||||
Text(code).tag(code)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Account")
|
||||
}
|
||||
|
||||
Section {
|
||||
Picker("Input Mode", selection: $inputMode) {
|
||||
ForEach(InputMode.allCases) { mode in
|
||||
Text(mode.title).tag(mode)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Input")
|
||||
} footer: {
|
||||
Text(inputMode.description)
|
||||
}
|
||||
|
||||
Section {
|
||||
Picker("Reminder Frequency", selection: $notificationFrequency) {
|
||||
ForEach(NotificationFrequency.allCases) { frequency in
|
||||
Text(frequency.displayName).tag(frequency)
|
||||
}
|
||||
}
|
||||
|
||||
if notificationFrequency == .custom {
|
||||
Stepper(
|
||||
"Every \(customFrequencyMonths) month\(customFrequencyMonths > 1 ? "s" : "")",
|
||||
value: $customFrequencyMonths,
|
||||
in: 1...24
|
||||
)
|
||||
}
|
||||
} header: {
|
||||
Text("Account Reminders")
|
||||
} footer: {
|
||||
Text("Reminders apply to the whole account.")
|
||||
}
|
||||
}
|
||||
.navigationTitle(account == nil ? "New Account" : "Edit Account")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("Cancel") { dismiss() }
|
||||
}
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Save") { saveAccount() }
|
||||
.disabled(!isValid)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
loadAccount()
|
||||
}
|
||||
}
|
||||
.presentationDetents([.large])
|
||||
}
|
||||
|
||||
private var isValid: Bool {
|
||||
!name.trimmingCharacters(in: .whitespaces).isEmpty
|
||||
}
|
||||
|
||||
private func loadAccount() {
|
||||
guard let account else { return }
|
||||
name = account.name
|
||||
currencyCode = account.currencyCode ?? currencyCode
|
||||
inputMode = InputMode(rawValue: account.inputMode) ?? .simple
|
||||
notificationFrequency = account.frequency
|
||||
customFrequencyMonths = Int(account.customFrequencyMonths)
|
||||
}
|
||||
|
||||
private func saveAccount() {
|
||||
if let account {
|
||||
accountRepository.updateAccount(
|
||||
account,
|
||||
name: name.trimmingCharacters(in: .whitespaces),
|
||||
currency: currencyCode,
|
||||
inputMode: inputMode,
|
||||
notificationFrequency: notificationFrequency,
|
||||
customFrequencyMonths: customFrequencyMonths
|
||||
)
|
||||
} else {
|
||||
_ = accountRepository.createAccount(
|
||||
name: name.trimmingCharacters(in: .whitespaces),
|
||||
currency: currencyCode,
|
||||
inputMode: inputMode,
|
||||
notificationFrequency: notificationFrequency,
|
||||
customFrequencyMonths: customFrequencyMonths
|
||||
)
|
||||
}
|
||||
|
||||
accountStore.persistSelection()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
AccountEditorView(account: nil)
|
||||
.environmentObject(AccountStore(iapService: IAPService()))
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import SwiftUI
|
||||
|
||||
struct AccountsView: View {
|
||||
@EnvironmentObject private var iapService: IAPService
|
||||
@EnvironmentObject private var accountStore: AccountStore
|
||||
@StateObject private var accountRepository = AccountRepository()
|
||||
@State private var showingAddAccount = false
|
||||
@State private var selectedAccount: Account?
|
||||
@State private var showingPaywall = false
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
AppBackground()
|
||||
|
||||
List {
|
||||
Section {
|
||||
ForEach(accountRepository.accounts) { account in
|
||||
Button {
|
||||
selectedAccount = account
|
||||
} label: {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text(account.name)
|
||||
.font(.headline)
|
||||
Text(account.currencyCode ?? AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currency)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
if accountStore.selectedAccount?.id == account.id && !accountStore.showAllAccounts {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.appPrimary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Accounts")
|
||||
} footer: {
|
||||
Text(iapService.isPremium ? "Create multiple accounts for business, family, or goals." : "Free users can create one account.")
|
||||
}
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
}
|
||||
.navigationTitle("Accounts")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button {
|
||||
if accountStore.canAddAccount() {
|
||||
showingAddAccount = true
|
||||
} else {
|
||||
showingPaywall = true
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showingAddAccount) {
|
||||
AccountEditorView(account: nil)
|
||||
}
|
||||
.sheet(isPresented: $showingPaywall) {
|
||||
PaywallView()
|
||||
}
|
||||
.sheet(item: $selectedAccount) { account in
|
||||
AccountEditorView(account: account)
|
||||
}
|
||||
.onAppear {
|
||||
accountRepository.fetchAccounts()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
AccountsView()
|
||||
.environmentObject(IAPService())
|
||||
.environmentObject(AccountStore(iapService: IAPService()))
|
||||
}
|
||||
Reference in New Issue
Block a user