Skip to content

Instantly share code, notes, and snippets.

@benigumocom
Last active December 7, 2023 07:51
Show Gist options
  • Save benigumocom/bd35b6e395ef8e18bd59d92086081dbc to your computer and use it in GitHub Desktop.
Save benigumocom/bd35b6e395ef8e18bd59d92086081dbc to your computer and use it in GitHub Desktop.
SwiftUI + SwiftData で ToDo リスト を作ってみる 👉 https://android.benigumo.com/20231128/swiftui-swiftdata-todo/
import Foundation
import SwiftData
@Model
final class Todo {
var text: String
var date: Date
init(text: String = "", date: Date = Date()) {
self.text = text
self.date = date
}
}
extension Date {
func string(format: String = "yyyy-MM-dd HH:mm:ss") -> String {
let formatter = DateFormatter()
formatter.dateFormat = format
return formatter.string(from: self)
}
}
import SwiftUI
import SwiftData
struct TodoList: View {
@Environment(\.modelContext) private var context
@Query(sort: \Todo.date) private var todos: [Todo]
@State private var selectedID: PersistentIdentifier?
@State private var bottomID: PersistentIdentifier?
@State private var text = ""
@FocusState var focused: Bool
var body: some View {
NavigationStack {
VStack(spacing: 0) {
ScrollView {
ForEach(todos) { todo in
LazyVStack(alignment: .leading) {
Text(todo.text)
.font(.headline)
Text(todo.date.string())
.font(.caption)
.foregroundStyle(.secondary)
}
.padding()
.foregroundStyle(selectedID == todo.id ? .white : .black)
.background(selectedID == todo.id ? .blue : .white)
.onTapGesture {
withAnimation {
if selectedID == todo.id {
clear()
} else {
selectedID = todo.id
text = todo.text
}
}
}
}
.padding()
.scrollTargetLayout()
}
.scrollPosition(id: $bottomID)
.onAppear {
withAnimation {
// for todo in todos {
// delete(todo: todo)
// }
// for i in 1 ..< 10000 {
// insert(text: "\(i) どうするのこれ")
// }
bottomID = todos.last?.id
}
}
HStack {
TextField("", text: $text)
.font(.system(.title3))
.textFieldStyle(.roundedBorder)
.focused($focused)
Button {
withAnimation {
if selectedID != nil {
update(todo: selectedTodo, text: text)
} else {
insert(text: text)
}
}
} label: {
Image(systemName: selectedID != nil ? "arrow.clockwise" : "plus")
.frame(height: 25)
}
.buttonStyle(.borderedProminent)
if selectedID != nil {
Button {
withAnimation {
delete(todo: selectedTodo)
}
} label: {
Image(systemName: "xmark")
.frame(height: 25)
}
.buttonStyle(.borderedProminent)
}
}
.padding()
}
.navigationTitle("Todo List")
}
}
private func insert(text: String) {
context.insert(Todo(text: text))
clear()
self.bottomID = todos.last?.id
}
private func delete(todo: Todo) {
context.delete(todo)
clear()
}
private func update(todo: Todo, text: String) {
delete(todo: todo)
insert(text: text)
clear()
}
private func clear() {
self.focused = false
self.text = ""
self.selectedID = nil
}
private var selectedTodo: Todo {
return todos.first(where: { todo in todo.id == selectedID })!
}
}
#Preview {
TodoList()
.modelContainer(for: Todo.self)
.frame(width: 300)
}
@benigumocom
Copy link
Author

【Swift】モデルクラスの ID に UUID() を使ってたらヤバい - PersistentIdentifier
👉 https://android.benigumo.com/20231205/persistentidentifier/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment