Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Refator/#131] UserDefaults -> SwiftData #134

Open
wants to merge 1 commit into
base: develop2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions PennyPack.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
18 changes: 17 additions & 1 deletion PennyPack/App/PennyPackApp.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}
24 changes: 4 additions & 20 deletions PennyPack/Magagers/ListManager.swift
Original file line number Diff line number Diff line change
@@ -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: 리스트에 새 값 추가 함수
Expand All @@ -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
}
}
}

}
32 changes: 8 additions & 24 deletions PennyPack/Magagers/ShoppingManager.swift
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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{
Expand Down
6 changes: 3 additions & 3 deletions PennyPack/ViewModels/CartViewModel.swift
Original file line number Diff line number Diff line change
@@ -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
Expand Down
9 changes: 5 additions & 4 deletions PennyPack/ViewModels/MainViewModel.swift
Original file line number Diff line number Diff line change
@@ -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
}
Expand Down
9 changes: 5 additions & 4 deletions PennyPack/Views/CartView/CartView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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?

Expand Down Expand Up @@ -213,7 +213,7 @@ struct CartView: View {
.foregroundColor(.pBlue)
}
}
ToolbarItem(placement: .principal){
ToolbarItem(placement: .principal) {
Text("장보기")
.font(.PTitle2)
.foregroundColor(.pWhite)
Expand All @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion PennyPack/Views/CartView/CustomAlertView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ struct CustomAlertView: View {

cartViewModel.shoppingManager.receiptDate.append(receiptDate)
cartViewModel.shoppingManager.cartItem = []
cartViewModel.shoppingManager.saveShoppingListToUserDefaults()
cartViewModel.shoppingManager

} label: {
Text("종료하기")
Expand Down
3 changes: 2 additions & 1 deletion PennyPack/Views/Components/DropdownListView.swift
Original file line number Diff line number Diff line change
@@ -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){
Expand Down
77 changes: 59 additions & 18 deletions PennyPack/Views/MainView/ListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()]))
}
19 changes: 11 additions & 8 deletions PennyPack/Views/MainView/MainView.swift
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -117,23 +120,23 @@ 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: {
Text("닫기")
}
}
case .cart:
CartView(cartViewModel: CartViewModel(shoppingManager: mainViewModel.shoppingManager, listManager: mainViewModel.listManager))
CartView(cartViewModel: CartViewModel(shoppingManager: mainViewModel.shoppingManager.first!, listManager: mainViewModel.listManager.first!))
}
}
}.navigationBarBackButtonHidden()
Expand All @@ -142,6 +145,6 @@ struct MainView: View {
}

#Preview {
MainView(mainViewModel: MainViewModel(shoppingManager: ShoppingManager(), listManager: ListManager()))
MainView(mainViewModel: MainViewModel(shoppingManager: [ShoppingManager()], listManager: [ListManager()]))
}