BudgetView.swift 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. //
  2. // BudgetView.swift
  3. // ydnab
  4. //
  5. // Created by Andrea Franceschini on 23/09/2020.
  6. //
  7. import SwiftUI
  8. struct BudgetCategoryCell: View {
  9. @State var category: BudgetCategory
  10. @State var amountText: String
  11. @State var color: Color
  12. var body: some View {
  13. HStack {
  14. Text(category.name)
  15. Spacer()
  16. Text(amountText)
  17. .bold()
  18. .foregroundColor(color)
  19. }
  20. }
  21. }
  22. struct BudgetSectionCell: View {
  23. @State var section: BudgetSection
  24. @State var amountText: String
  25. @State var color: Color
  26. @Environment(\.editMode) var editMode
  27. var body: some View {
  28. HStack {
  29. Text(section.name)
  30. .textCase(.none)
  31. Spacer()
  32. if editMode?.wrappedValue == .inactive {
  33. Text(amountText)
  34. .foregroundColor(color)
  35. }
  36. }
  37. .padding(.vertical, 11)
  38. }
  39. }
  40. struct YearAndMonthPicker: View {
  41. @Binding var month: Int
  42. @Binding var year: Int
  43. @State var locale: Locale
  44. private var monthNames: [String] {
  45. var c = Calendar(identifier: .gregorian)
  46. c.locale = locale
  47. return c.monthSymbols
  48. }
  49. var body: some View {
  50. VStack {
  51. HStack {
  52. Button(action: { print(self) }) {
  53. Image(systemName: "chevron.backward.square")
  54. .imageScale(.large)
  55. }
  56. Spacer()
  57. Text("\(year)").bold()
  58. Spacer()
  59. Button(action: {}) {
  60. Image(systemName: "chevron.forward.square")
  61. .imageScale(.large)
  62. }
  63. }
  64. // GridStack(rows: 4, columns: 3) { row, col in
  65. // Button(monthNames[row+col], action: { month = row+col+1 })
  66. // }
  67. // ScrollView(.horizontal) {
  68. LazyHGrid(rows: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())], alignment: .top, spacing: nil, pinnedViews: []) {
  69. ForEach(0..<monthNames.count) { i in
  70. Button(monthNames[i], action: { month = i+1 }).padding(40)
  71. }
  72. // }
  73. }
  74. }
  75. .padding(.bottom, 11)
  76. }
  77. }
  78. struct BudgetViewSummary: View {
  79. @Binding var budget: BudgetInfo
  80. @Binding var month: Int
  81. @Binding var year: Int
  82. @State private var showMonthPicker: Bool = true
  83. var body: some View {
  84. VStack {
  85. HStack {
  86. Button("\(month)", action: { withAnimation() { showMonthPicker.toggle() } } )
  87. Spacer()
  88. }
  89. .padding(.vertical, 11)
  90. if showMonthPicker {
  91. YearAndMonthPicker(month: $month, year: $year, locale: Locale(identifier: budget.localeIdentifier))
  92. }
  93. HStack {
  94. Text("To budget") // Or "overbudgeted"
  95. Spacer()
  96. Text("$ 0.00")
  97. }
  98. }
  99. .padding(.vertical, 11)
  100. }
  101. }
  102. struct BudgetView: View {
  103. @State var budget: BudgetInfo
  104. @Binding var currentBudgetId: UUID?
  105. @State private var month: Int = 0
  106. @State private var year: Int = 0
  107. @AppStorage("lastLoadedBudgetId") private var lastLoadedBudgetId = ""
  108. func formatAmount(_ amount: NSNumber) -> String? {
  109. let f = NumberFormatter()
  110. f.locale = Locale(identifier: budget.localeIdentifier)
  111. f.numberStyle = .currency
  112. return f.string(from: amount)
  113. }
  114. var body: some View {
  115. VStack {
  116. BudgetViewSummary(budget: $budget, month: $month, year: $year)
  117. .padding([.leading, .trailing], 16)
  118. List {
  119. ForEach(budget.sections) { section in
  120. if !section.hidden {
  121. Section(header: BudgetSectionCell(section: section,
  122. amountText: formatAmount(0) ?? "--",
  123. color: 0 < 0 ? Color("negativeAmount") : Color("positiveAmount"))
  124. ) {
  125. ForEach(section.categories) { category in
  126. if !category.hidden {
  127. BudgetCategoryCell(category: category,
  128. amountText: formatAmount(0) ?? "--",
  129. color: 0 < 0 ? Color("negativeAmount") : Color("positiveAmount")
  130. )
  131. }
  132. }
  133. .onMove { (indexSet, s) in
  134. print(indexSet, s)
  135. }
  136. }
  137. }
  138. }
  139. .onMove { (indexSet, s) in
  140. print(indexSet, s)
  141. }
  142. }
  143. .listStyle(PlainListStyle())
  144. .navigationBarTitle(budget.name, displayMode: .inline)
  145. .toolbar {
  146. EditButton()
  147. }
  148. .onAppear() {
  149. print("BudgetView Appears")
  150. currentBudgetId = budget.id
  151. lastLoadedBudgetId = budget.id.uuidString
  152. }
  153. }
  154. }
  155. }
  156. struct BudgetView_Previews: PreviewProvider {
  157. static let budget: [BudgetSection] = [
  158. BudgetSection(name: "Everyday Expenses", categories: [
  159. BudgetCategory(name: "Groceries"),
  160. BudgetCategory(name: "Eating out"),
  161. BudgetCategory(name: "Medical"),
  162. BudgetCategory(name: "Clothing"),
  163. BudgetCategory(name: "Household goods")
  164. ]),
  165. BudgetSection(name: "Travel", categories: [
  166. BudgetCategory(name: "Transport"),
  167. BudgetCategory(name: "Fuel"),
  168. BudgetCategory(name: "Accommodation")
  169. ]),
  170. BudgetSection(name: "Rainy Days", categories: [
  171. BudgetCategory(name: "Emergencies"),
  172. BudgetCategory(name: "Car insurance")
  173. ]),
  174. BudgetSection(name: "Monthly Expenses", categories: [
  175. BudgetCategory(name: "Rent"),
  176. BudgetCategory(name: "Mobile")
  177. ]),
  178. BudgetSection(name: "Savings Goals", categories: [
  179. BudgetCategory(name: "Savings"),
  180. BudgetCategory(name: "Holidays")
  181. ])
  182. ]
  183. @State static var currentBudgetId: UUID?
  184. static var previews: some View {
  185. NavigationView {
  186. BudgetView(budget: BudgetInfo(name: "Default Budget", sections: budget),
  187. currentBudgetId: $currentBudgetId)
  188. }
  189. .preferredColorScheme(.light)
  190. //.environment(\.layoutDirection, .rightToLeft)
  191. }
  192. }