How can I save my sublists and todos in SwiftUI?

53 views Asked by At

my problem is that when I open the SingleListView and add more elements, they are the same for every SingleListView of a list. I also know the reason for this (The SingleListView works "together" with the Construction and the Listen_View and is not included in the ListData struct) but I don't know how to solve this directly, I hope someone of you can help me.

Many thanks in advance.

import SwiftUI

struct TodoData: Identifiable, Codable, Equatable {
    let id = UUID()
    var name: String
}

struct ListData: Identifiable, Codable, Equatable {
    let id = UUID()
    var name: String
    var emoji: String
    let items: Int
    var color: String
    
    var isEditing = false
    
    init(name: String, emoji: String, items: Int, color: String) {
        self.name = name
        self.emoji = emoji
        self.items = items
        self.color = color
    }
}
//main list view
struct Listen_View: View {
    @StateObject var viewModel = SettingsViewModel()
    
    @AppStorage("lists") private var storedListsData: Data?
    @AppStorage("todos") private var storedTodosData: Data?
    
    @State private var newListName = ""
    @StateObject var appStorageHelper = AppStorageHelperProfilImage()
    @State private var selectedImage: UIImage?
    @State private var isProfileImagePickerPresented = false
    @State private var isAddingItem = false
    @State private var isAddListViewPresented = false
    @State private var lists = [ListData]()
    
    let availableColors: [String] = ["rosa", "marineblau", "lila", "gelb"]
    let availableEmojis: [String] = ["", "✅", "", ""] // Beispiel-Emojis
    
    var body: some View {
        NavigationView {
            ZStack {
                Color("marineblau")
                    .ignoresSafeArea()
                
                VStack {
                    HStack {
                        Spacer()
                        
                        Button(action: {
                            addList()
                        }) {
                            Image(systemName: "plus")
                                .resizable()
                                .frame(width: 30, height: 30)
                                .foregroundColor(.white)
                                .padding()
                        }
                        
                        Spacer()
                        
                        Text("Listen")
                            .font(.largeTitle)
                            .fontWeight(.bold)
                            .padding()
                            .foregroundStyle(.white)
                            .frame(width: 250)
                        
                        Spacer()
                        
                        NavigationLink{
                            Setting_main_view()
                            
                        }label: {
                            
                            Image(uiImage: (selectedImage ?? UIImage(systemName: "person.circle"))!)
                                .resizable()
                                .scaledToFill()
                                .frame(width: 50, height: 50)
                                .clipShape(Circle())
                                .id(appStorageHelper.selectedImage)
                                .onAppear {
                                    if selectedImage == nil {
                                        if let loadedImage = AppStorageHelperProfilImage.loadProfileImage() {
                                            selectedImage = loadedImage
                                        }
                                    }
                                }
                        }
                        
                        Spacer()
                    }
                    
                    Spacer()
                    
                    ScrollView {
                        LazyVGrid(columns: [GridItem(.flexible(), spacing: 20), GridItem(.flexible(), spacing: 20)], spacing: 20) {
                            ForEach(lists.indices, id: \.self) { index in
                                ListViewConstruction(list: $lists[index]) {
                                    saveLists()
                                }
                                .padding()
                                .contextMenu {
                                    ColorMenu(listIndex: index)
                                    EmojiMenu(listIndex: index)
                                    DeleteMenu(listIndex: index)
                                }
                            }
                        }
                    }
                    .background(Color("white"))
                    .clipShape(
                        .rect(
                            topLeadingRadius: 25,
                            bottomLeadingRadius: 0,
                            bottomTrailingRadius: 0,
                            topTrailingRadius: 25
                        )
                    )
                    .frame(maxHeight: .infinity)
                }
            }
            .onAppear {
                restoreLists()
            }
        }
        .navigationViewStyle(.stack)
        .environmentObject(viewModel)
    }
    
    private func addList() {
        let newList = ListData(name: "Neue Liste", emoji: "", items: 0, color: "lila")
        lists.append(newList)
        saveLists()
    }
    
    private func ColorMenu(listIndex: Int) -> some View {
        Menu {
            ForEach(availableColors, id: \.self) { color in
                Button(action: {
                    lists[listIndex].color = color
                    saveLists()
                }) {
                    Text(color.capitalized)
                }
            }
        } label: {
            Text("Farbe ändern")
            Image(systemName: "paintpalette")
        }
    }
    
    private func EmojiMenu(listIndex: Int) -> some View {
        Menu {
            ForEach(availableEmojis, id: \.self) { emoji in
                Button(action: {
                    lists[listIndex].emoji = emoji
                    saveLists()
                }) {
                    Text(emoji)
                }
            }
        } label: {
            Text("Emoji ändern")
            Image(systemName: "smiley")
        }
    }
    
    private func DeleteMenu(listIndex: Int) -> some View {
        Button(action: {
            lists.remove(at: listIndex)
            saveLists()
        }) {
            Text("Löschen")
            Image(systemName: "trash")
        }
    }
    
    private func saveLists() {
        do {
            let data = try JSONEncoder().encode(lists)
            storedListsData = data
        } catch {
            print("Error encoding lists: \(error)")
        }
    }
    
    private func restoreLists() {
        guard let data = storedListsData else { return }
        do {
            lists = try JSONDecoder().decode([ListData].self, from: data)
        } catch {
            print("Error decoding lists: \(error)")
        }
    }
}

struct SingleListView: View {
    @Binding var list: ListData
        @State var todos = [TodoData]()
        @State var lists = [ListData]()
        @State var newTodoName = ""
        @State var newSublistName = ""
        @State var isAddingItemMenuPresented = false
        
        @AppStorage("sublists") private var storedSublistsData: Data?
        @AppStorage("todos") private var storedTodosData: Data?
        
        @State private var newListName = ""
        @StateObject var appStorageHelper = AppStorageHelperProfilImage()
        @State private var selectedImage: UIImage?
        @State private var isProfileImagePickerPresented = false
        @State private var isAddingItem = false
        @State private var isAddListViewPresented = false
        
        let availableColors: [String] = ["rosa", "marineblau", "lila", "gelb"]
        let availableEmojis: [String] = ["", "✅", "", ""] // Beispiel-Emojis
    
    var body: some View {
        VStack {
            
            ScrollView {
                LazyVStack(spacing: 10) {
                    ForEach(todos) { todo in
                        TodoView(todo: todo)
                    }
                }
            }
            .navigationBarTitle("Single List View", displayMode: .inline)
            
            HStack {
                Spacer()
                Button(action: {
                    isAddingItemMenuPresented.toggle()
                }) {
                    Image(systemName: "plus")
                }
                .padding()
                .foregroundColor(.blue)
            }
            .actionSheet(isPresented: $isAddingItemMenuPresented) {
                ActionSheet(title: Text("Hinzufügen"), buttons: [
                    .default(Text("Todo hinzufügen")) {
                        addTodo()
                    },
                    .default(Text("Unterliste hinzufügen")) {
                        addList()
                    },
                    .cancel()
                ])
            }
            
            ScrollView {
                LazyVGrid(columns: [GridItem(.flexible(), spacing: 20), GridItem(.flexible(), spacing: 20)], spacing: 20) {
                    ForEach(lists.indices, id: \.self) { index in
                        ListViewConstruction(list: $lists[index]) {
                            //code
                        }
                        .padding()
                        .contextMenu {
                            ColorMenu(listIndex: index)
                            EmojiMenu(listIndex: index)
                            DeleteMenu(listIndex: index)
                        }
                    }
                }
            }
        }
        .sheet(isPresented: $isAddListViewPresented) {
            AddToDoListView(todos: $todos)
        }
        .navigationViewStyle(.stack)
        .onAppear {
                    restoreTodos()
                    restoreSublists()
                }
                .onChange(of: todos) { _ in
                    saveTodos()
                }
                .onChange(of: lists) { _ in
                    saveSublists()
                }
    }
    
    private func addTodo() {
        todos.append(TodoData(name: newTodoName))
        newTodoName = ""
    }
    
    private func addList() {
        let newList = ListData(name: "Neue Liste", emoji: "", items: 0, color: "lila")
        lists.append(newList)
    }
    
    private func ColorMenu(listIndex: Int) -> some View {
        Menu {
            ForEach(availableColors, id: \.self) { color in
                Button(action: {
                    lists[listIndex].color = color
                    
                }) {
                    Text(color.capitalized)
                }
            }
        } label: {
            Text("Farbe ändern")
            Image(systemName: "paintpalette")
        }
    }
    
    private func EmojiMenu(listIndex: Int) -> some View {
        Menu {
            ForEach(availableEmojis, id: \.self) { emoji in
                Button(action: {
                    lists[listIndex].emoji = emoji
                    
                }) {
                    Text(emoji)
                }
            }
        } label: {
            Text("Emoji ändern")
            Image(systemName: "smiley")
        }
    }
    
    private func DeleteMenu(listIndex: Int) -> some View {
        Button(action: {
            lists.remove(at: listIndex)
            
        }) {
            Text("Löschen")
            Image(systemName: "trash")
        }
    }
    private func saveTodos() {
            do {
                let data = try JSONEncoder().encode(todos)
                storedTodosData = data
            } catch {
                print("Error encoding todos: \(error)")
            }
        }
        
        private func restoreTodos() {
            guard let data = storedTodosData else { return }
            do {
                todos = try JSONDecoder().decode([TodoData].self, from: data)
            } catch {
                print("Error decoding todos: \(error)")
            }
        }
        
        private func saveSublists() {
            do {
                let data = try JSONEncoder().encode(lists)
                storedSublistsData = data
            } catch {
                print("Error encoding sublists: \(error)")
            }
        }
        
        private func restoreSublists() {
            guard let data = storedSublistsData else { return }
            do {
                lists = try JSONDecoder().decode([ListData].self, from: data)
            } catch {
                print("Error decoding sublists: \(error)")
            }
        }
    
}

struct ListViewConstruction: View {
    @Binding var list: ListData
    var onSave: () -> Void
    
    var body: some View {
        VStack {
            HStack {
                NavigationLink(destination: SingleListView(list: $list)) {
                    Text(list.emoji)
                        .font(.system(size: 50))
                        .padding()
                }
            }
            .padding()
            .background(Color(list.color))
            .cornerRadius(20)
            .padding()
            
            VStack {
                HStack{
                    Spacer()
                    if list.isEditing {
                        TextField("Listenname", text: $list.name, onCommit: {
                            list.isEditing.toggle()
                            onSave() // Speichern, wenn die Bearbeitung abgeschlossen ist
                        })
                        .font(.title2)
                        .background(.clear)
                        
                    } else {
                        HStack {
                            Text(list.name)
                                .font(.title2)
                                .onTapGesture {
                                    list.isEditing.toggle()
                                }
                        }
                    }
                    Spacer()
                }
                HStack {
                    Spacer()
                    Text("\(list.items) Items")
                        .font(.callout)
                        .foregroundStyle(.gray)
                    Spacer()
                    
                }
            }
            
            .padding(.bottom)
        }
    }
}

struct TodoView: View {
    var todo: TodoData
    
    var body: some View {
        HStack {
            Button(action: {
                // Hier können Sie die Logik zum Abhaken des Todos implementieren
            }) {
                Image(systemName: "square")
                    .resizable()
                    .frame(width: 20, height: 20)
            }
            
            Text(todo.name)
            
            Spacer()
        }
        .padding()
    }
}



0

There are 0 answers