Skip to content

Instantly share code, notes, and snippets.

@treboc
Created July 29, 2023 09:37
Show Gist options
  • Save treboc/0030121e1da7e4655716cc14582b59cd to your computer and use it in GitHub Desktop.
Save treboc/0030121e1da7e4655716cc14582b59cd to your computer and use it in GitHub Desktop.
// 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