diff --git a/PennyPack.xcodeproj/project.pbxproj b/PennyPack.xcodeproj/project.pbxproj index 175075f..4ef9143 100644 --- a/PennyPack.xcodeproj/project.pbxproj +++ b/PennyPack.xcodeproj/project.pbxproj @@ -584,7 +584,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"PennyPack/Preview Content\""; - DEVELOPMENT_TEAM = R83JF9K5WA; + DEVELOPMENT_TEAM = 7P4U6S44RJ; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PennyPack/Info.plist; @@ -624,7 +624,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"PennyPack/Preview Content\""; - DEVELOPMENT_TEAM = R83JF9K5WA; + DEVELOPMENT_TEAM = 7P4U6S44RJ; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PennyPack/Info.plist; diff --git a/PennyPack/App/PennyPackApp.swift b/PennyPack/App/PennyPackApp.swift index 2d56928..d534b46 100644 --- a/PennyPack/App/PennyPackApp.swift +++ b/PennyPack/App/PennyPackApp.swift @@ -1,11 +1,27 @@ import SwiftUI +import SwiftData @main struct PennyPackApp: App { + var modelContainer: ModelContainer = { + let schema = Schema([ListManager.self, ShoppingManager.self]) // ModelContainer를 생성하려면 우선 사용할 모델들을 스키마로 만들어준다. + let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) + // ModelConfiguration을 생성해 모델 관리 규칙을 설정해준다. + // ModelConfiguration 옵션으로는 여러 가지가 있는데, (프리뷰 등에서 데이터를 메모리 상에서만 관리할지 여부를 결정하는) inStoredInMemoryOnly, (CloudKit을 사용할 때 데이터베이스를 설정하는) cloudKitbataBase 등이 있다. + + do { + return try ModelContainer(for: schema, configurations: [modelConfiguration]) + } catch { + fatalError("Could not create ModelContainer: \(error)") + } + // 마지막으로 이렇게 만든 Schema와 ModelConfiguration을 사용해 ModelContainer를 만들어준다. + }() + var body: some Scene { WindowGroup { - MainView(mainViewModel: MainViewModel(shoppingManager: ShoppingManager(), listManager: ListManager())) + MainView(mainViewModel: MainViewModel(shoppingManager: [ShoppingManager()], listManager: [ListManager()])) } + .modelContainer(modelContainer) } } diff --git a/PennyPack/Magagers/ListManager.swift b/PennyPack/Magagers/ListManager.swift index 316706a..e8431d8 100644 --- a/PennyPack/Magagers/ListManager.swift +++ b/PennyPack/Magagers/ListManager.swift @@ -1,10 +1,11 @@ import Foundation +import SwiftData -class ListManager: ObservableObject { - @Published var shoppingList: [ShoppingList] = [] +@Model +class ListManager { + @Relationship var shoppingList: [ShoppingList] = [] init() { - loadShoppingListFromUserDefaults() } // MARK: 리스트에 새 값 추가 함수 @@ -24,24 +25,7 @@ class ListManager: ObservableObject { func removeList(at offsets: IndexSet) { shoppingList.remove(atOffsets: offsets) - saveShoppingListToUserDefaults() print("Updated shoppingList: \(shoppingList)") } - - // MARK: 데이터를 인코딩하고 UserDefaults에 저장 - func saveShoppingListToUserDefaults() { - if let encoded = try? JSONEncoder().encode(shoppingList) { - UserDefaults.standard.set(encoded, forKey: "shoppingList") - } - } - - func loadShoppingListFromUserDefaults() { - if let savedData = UserDefaults.standard.data(forKey: "shoppingList") { - if let saveLists = try? JSONDecoder().decode([ShoppingList].self, from: savedData) { - self.shoppingList = saveLists - } - } - } - } diff --git a/PennyPack/Magagers/ShoppingManager.swift b/PennyPack/Magagers/ShoppingManager.swift index 98a51f9..be06056 100644 --- a/PennyPack/Magagers/ShoppingManager.swift +++ b/PennyPack/Magagers/ShoppingManager.swift @@ -1,15 +1,16 @@ import Foundation +import SwiftData -class ShoppingManager:ObservableObject { - @Published var receiptDate: [ReceiptDate] = [] - @Published var cartItem: [CartItem] = [] - @Published var selectedReceiptDate: ReceiptDate? +@Model +class ShoppingManager { + var receiptDate: [ReceiptDate] = [] + var cartItem: [CartItem] = [] + var selectedReceiptDate: ReceiptDate? - @Published var nowBudget: Int? - @Published var nowPlace: String = "" + var nowBudget: Int? + var nowPlace: String = "" init(){ - loadShoppingListFromUserDefaults() } // MARK: 리스트에 새 값 추가 함수 func addNewCartItem(korName: String, frcName: String, quantity: Int, korUnitPrice: Int, frcUnitPrice: Double) -> CartItem { @@ -23,25 +24,8 @@ class ShoppingManager:ObservableObject { print("Updated shoppingList: \(cartItem)") } - // MARK: 데이터를 인코딩하고 UserDefaults에 저장 - func saveShoppingListToUserDefaults() { - if let encoded = try? JSONEncoder().encode(receiptDate) { - UserDefaults.standard.set(encoded, forKey: "receiptDate") - } - - print("save 됨") - } - // MARK: UserDefaults에서 데이터를 불러오기 func loadShoppingListFromUserDefaults() { - if let savedData = UserDefaults.standard.data(forKey: "receiptDate") { - if let saveLists = try? JSONDecoder().decode([ReceiptDate].self, from: savedData){ - receiptDate = saveLists - } - } - print("load 됨") - print("*******************************") - for item in receiptDate { print("날짜: \(item.date)") for index in item.items{ diff --git a/PennyPack/ViewModels/CartViewModel.swift b/PennyPack/ViewModels/CartViewModel.swift index e046e47..dceb525 100644 --- a/PennyPack/ViewModels/CartViewModel.swift +++ b/PennyPack/ViewModels/CartViewModel.swift @@ -1,9 +1,9 @@ import Foundation import SwiftUI -class CartViewModel: ObservableObject{ - @Published var shoppingManager: ShoppingManager - @Published var listManager: ListManager +class CartViewModel: ObservableObject { + @Bindable var shoppingManager: ShoppingManager + @Bindable var listManager: ListManager @Published var recognizedText = "" @Published var isAlert: Bool = false diff --git a/PennyPack/ViewModels/MainViewModel.swift b/PennyPack/ViewModels/MainViewModel.swift index 3f67b66..560999c 100644 --- a/PennyPack/ViewModels/MainViewModel.swift +++ b/PennyPack/ViewModels/MainViewModel.swift @@ -1,11 +1,12 @@ import Foundation import SwiftUI +import SwiftData -class MainViewModel: ObservableObject{ - @Published var shoppingManager: ShoppingManager - @Published var listManager: ListManager +class MainViewModel: ObservableObject { + @Published var shoppingManager: [ShoppingManager] + @Published var listManager: [ListManager] - init(shoppingManager: ShoppingManager, listManager: ListManager) { + init(shoppingManager: [ShoppingManager], listManager: [ListManager]) { self.shoppingManager = shoppingManager self.listManager = listManager } diff --git a/PennyPack/Views/CartView/CartView.swift b/PennyPack/Views/CartView/CartView.swift index 74624c0..67e6a7e 100644 --- a/PennyPack/Views/CartView/CartView.swift +++ b/PennyPack/Views/CartView/CartView.swift @@ -4,7 +4,7 @@ import SwiftUI struct CartView: View { @EnvironmentObject var pathRouter: PathRouter @Environment(\.dismiss) var dismiss - @ObservedObject var cartViewModel: CartViewModel + @StateObject var cartViewModel: CartViewModel @FocusState var focusedField: Field? @@ -213,7 +213,7 @@ struct CartView: View { .foregroundColor(.pBlue) } } - ToolbarItem(placement: .principal){ + ToolbarItem(placement: .principal) { Text("장보기") .font(.PTitle2) .foregroundColor(.pWhite) @@ -226,7 +226,7 @@ struct CartView: View { cartViewModel.listManager.shoppingList[index].isPurchase = cartViewModel.listManager.shoppingList[index].isChoise } - cartViewModel.listManager.saveShoppingListToUserDefaults() +// cartViewModel.listManager.saveShoppingListToUserDefaults() }) { Text("종료") .foregroundColor(.pBlue) @@ -265,7 +265,8 @@ struct CartView: View { } .hideKeyboard() - HStack(spacing: 0){ TextField("1", text: Binding( + HStack(spacing: 0){ + TextField("1", text: Binding( get: { String(cartViewModel.shoppingManager.cartItem[index].quantity) }, set: { newValue in if let intValue = Int(newValue) { diff --git a/PennyPack/Views/CartView/CustomAlertView.swift b/PennyPack/Views/CartView/CustomAlertView.swift index 568f7a7..0be0a92 100644 --- a/PennyPack/Views/CartView/CustomAlertView.swift +++ b/PennyPack/Views/CartView/CustomAlertView.swift @@ -66,7 +66,7 @@ struct CustomAlertView: View { cartViewModel.shoppingManager.receiptDate.append(receiptDate) cartViewModel.shoppingManager.cartItem = [] - cartViewModel.shoppingManager.saveShoppingListToUserDefaults() + cartViewModel.shoppingManager } label: { Text("종료하기") diff --git a/PennyPack/Views/Components/DropdownListView.swift b/PennyPack/Views/Components/DropdownListView.swift index 4be4443..560d609 100644 --- a/PennyPack/Views/Components/DropdownListView.swift +++ b/PennyPack/Views/Components/DropdownListView.swift @@ -1,7 +1,8 @@ import SwiftUI struct DropdownListView: View { - @ObservedObject var listManager: ListManager + @Environment(\.modelContext) private var context + @Bindable var listManager: ListManager var body: some View { VStack(spacing: 0){ diff --git a/PennyPack/Views/MainView/ListView.swift b/PennyPack/Views/MainView/ListView.swift index 32daa87..f2f4b7b 100644 --- a/PennyPack/Views/MainView/ListView.swift +++ b/PennyPack/Views/MainView/ListView.swift @@ -5,23 +5,58 @@ struct ListView: View { var body: some View { VStack{ List{ - ForEach($mainViewModel.listManager.shoppingList, id: \.id){ $item in - if !item.isPurchase { - TextField("마트에서 살 물건을 이곳에 적어주세요.", text: $item.title) + if let firstListManager = mainViewModel.listManager.first { +// ForEach($mainViewModel.listManager.shoppingList, id: \.id){ $item in +// if !item.isPurchase { +// TextField("마트에서 살 물건을 이곳에 적어주세요.", text: $item.title) +// .onSubmit { +// mainViewModel.listManager +// } +// } +// } + ForEach(firstListManager.shoppingList, id: \.id) { item in + if !item.isPurchase { + TextField("마트에서 살 물건을 이곳에 적어주세요.", text: Binding( + get: { item.title }, + set: { newValue in + if let index = firstListManager.shoppingList.firstIndex(where: { $0.id == item.id }) { + firstListManager.shoppingList[index].title = newValue + } + } + )) .onSubmit { - mainViewModel.listManager.saveShoppingListToUserDefaults() + // addList 호출은 데이터 모델로 위임 + firstListManager.addList(title: "새로운 항목") } + } + } + .onDelete { indexSet in + // 삭제 처리: firstListManager에서 해당 항목 삭제 + firstListManager.removeList(at: indexSet) } + } else { + Text("목록이 비어 있어요!") } - .onDelete(perform: mainViewModel.listManager.removeList) - .listRowSeparator(.hidden) - .listRowBackground( - Rectangle() - .foregroundColor(.pWhite) - .cornerRadius(12) - ) + // ForEach($mainViewModel.listManager.shoppingList, id: \.id){ $item in + // if !item.isPurchase { + // TextField("마트에서 살 물건을 이곳에 적어주세요.", text: $item.title) + // .onSubmit { + // mainViewModel.listManager + // } + // } + // } + // .onDelete(perform: mainViewModel.listManager.removeList) + // .listRowSeparator(.hidden) + // .listRowBackground( + // Rectangle() + // .foregroundColor(.pWhite) + // .cornerRadius(12) + // ) Button { - mainViewModel.listManager.addList(title: "") +// mainViewModel.listManager.addList(title: "") + if let firstListManager = mainViewModel.listManager.first { + firstListManager.addList(title: "새로운 항목") + } } label: { HStack{ Spacer() @@ -36,20 +71,26 @@ struct ListView: View { Spacer() } } .listRowSeparator(.hidden) - .listRowBackground( - Rectangle() - .foregroundColor(.pWhite) - .cornerRadius(12) - ) + .listRowBackground( + Rectangle() + .foregroundColor(.pWhite) + .cornerRadius(12) + ) } .listRowSpacing(8) .listStyle(PlainListStyle()) .padding(.horizontal) .background(.pLightGray) + .listRowSeparator(.hidden) + .listRowBackground( + Rectangle() + .foregroundColor(.pWhite) + .cornerRadius(12) + ) } } } #Preview { - ListView(mainViewModel: MainViewModel(shoppingManager: ShoppingManager(), listManager: ListManager())) + ListView(mainViewModel: MainViewModel(shoppingManager: [ShoppingManager()], listManager: [ListManager()])) } diff --git a/PennyPack/Views/MainView/MainView.swift b/PennyPack/Views/MainView/MainView.swift index 08d4118..130f3eb 100644 --- a/PennyPack/Views/MainView/MainView.swift +++ b/PennyPack/Views/MainView/MainView.swift @@ -1,8 +1,9 @@ import SwiftUI struct MainView: View { + @Environment(\.modelContext) var modelContext @StateObject var pathRouter = PathRouter() - @StateObject var mainViewModel = MainViewModel(shoppingManager: ShoppingManager(), listManager: ListManager()) + @StateObject var mainViewModel = MainViewModel(shoppingManager: [ShoppingManager()], listManager: [ListManager()]) var body: some View { NavigationStack(path: $pathRouter.path) { @@ -17,7 +18,7 @@ struct MainView: View { .foregroundColor(.pWhite) Spacer() NavigationLink( - destination: CalendarView(calendarViewModel: CalendarViewModel(shoppingManager: mainViewModel.shoppingManager, listManager: mainViewModel.listManager)), + destination: CalendarView(calendarViewModel: CalendarViewModel(shoppingManager: mainViewModel.shoppingManager.first!, listManager: mainViewModel.listManager.first!)), label: { Image(systemName: "calendar") .font(.system(size: 24)) @@ -57,7 +58,9 @@ struct MainView: View { VStack(spacing: 0){ HStack{ Button{ - mainViewModel.listManager.addListShowcase(title: "") +// mainViewModel.listManager.addListShowcase(title: "") + mainViewModel.listManager.first?.addListShowcase(title: "") // 배열에서 첫 번째 ListManager 객체를 선택하여 메서드 호출 + } label: { Text("오늘의 장보기 리스트") .font(.PTitle2) @@ -117,15 +120,15 @@ struct MainView: View { } .onAppear{ - mainViewModel.shoppingManager.loadShoppingListFromUserDefaults() - mainViewModel.listManager.loadShoppingListFromUserDefaults() + mainViewModel.shoppingManager + mainViewModel.listManager } .environmentObject(pathRouter) .navigationDestination(for: NavigationRoute.self) { route in switch route { case .result: VStack { - ResultView(resultViewModel: ResultViewModel(shoppingManager: mainViewModel.shoppingManager, listManager: mainViewModel.listManager)) + ResultView(resultViewModel: ResultViewModel(shoppingManager: mainViewModel.shoppingManager.first!, listManager: mainViewModel.listManager.first!)) Button { pathRouter.removeAll() } label: { @@ -133,7 +136,7 @@ struct MainView: View { } } case .cart: - CartView(cartViewModel: CartViewModel(shoppingManager: mainViewModel.shoppingManager, listManager: mainViewModel.listManager)) + CartView(cartViewModel: CartViewModel(shoppingManager: mainViewModel.shoppingManager.first!, listManager: mainViewModel.listManager.first!)) } } }.navigationBarBackButtonHidden() @@ -142,6 +145,6 @@ struct MainView: View { } #Preview { - MainView(mainViewModel: MainViewModel(shoppingManager: ShoppingManager(), listManager: ListManager())) + MainView(mainViewModel: MainViewModel(shoppingManager: [ShoppingManager()], listManager: [ListManager()])) }