Created
July 29, 2023 09:37
-
-
Save treboc/0030121e1da7e4655716cc14582b59cd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Created by Marvin Lee Kobert on 29.07.23. | |
// | |
// | |
import SwiftUI | |
// MARK: Item Model | |
struct Item: Identifiable, Hashable { | |
let id: UUID | |
let title: String | |
let subitems: [Item] | |
init(id: UUID = .init(), title: String, subitems: [Item] = []) { | |
self.id = id | |
self.title = title | |
self.subitems = subitems | |
} | |
} | |
// MARK: ViewModel | |
final class ViewModel: ObservableObject { | |
@Published var items: [Item] | |
init() { | |
self.items = Self.sampleItems() | |
} | |
func persist(item: Item, withID id: UUID) { | |
guard let index = items.firstIndex(where: { $0.id == id }) else { | |
print("Cannot find item") | |
return | |
} | |
items[index] = item | |
} | |
private static func sampleItems() -> [Item] { | |
let subItems: [Item] = [.init(title: "First Subitem"), .init(title: "Second Subitem")] | |
return [.init(title: "First Item", subitems: subItems)] | |
} | |
} | |
// MARK: Master View | |
struct MasterView: View { | |
@StateObject private var viewModel = ViewModel() | |
var body: some View { | |
NavigationStack { | |
List { | |
// You need to identify the item over the hashValue, so the list will redraw if the title or subitems change, | |
// because the id is fixed. | |
ForEach(viewModel.items, id: \.hashValue) { item in | |
NavigationLink(item.title) { | |
DetailView(item: item) | |
} | |
} | |
} | |
.navigationTitle("Items") | |
} | |
.environmentObject(viewModel) | |
} | |
} | |
struct DetailView: View { | |
@EnvironmentObject private var viewModel: ViewModel | |
@Environment(\.dismiss) private var dismiss | |
let item: Item | |
@State private var title: String | |
init(item: Item) { | |
self.item = item | |
self._title = .init(initialValue: item.title) | |
} | |
var body: some View { | |
Form { | |
Section { | |
Text("Trying to change the text in the title textfield **in the middle of the text** unexpectedly moves the cursor to the end of the text.") | |
.font(.caption) | |
.padding() | |
} | |
Section("Title Textfield") { | |
TextField("", text: $title) | |
} | |
Section("Subitems") { | |
ForEach(item.subitems) { subitem in | |
NavigationLink { | |
DetailView(item: subitem) | |
} label: { | |
Text(subitem.title) | |
} | |
} | |
} | |
Section { | |
Button("Save") { | |
// Generate a new Item with the ID and subitems from the old item, with the new title | |
let newItem: Item = .init(id: item.id, title: title, subitems: item.subitems) | |
viewModel.persist(item: newItem, withID: item.id) | |
dismiss() | |
} | |
} | |
} | |
} | |
} | |
struct MasterView_Previews: PreviewProvider { | |
static var previews: some View { | |
MasterView() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment