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()
}
}