| I might do that at some point... this is the main part of it, just a swift data model and one file of views. Plus a bunch of example code for making widgets work. ```
import Foundation
import SwiftData @Model
final class FocusItem {
let created: Date = Date()
var completed: Date?
var theFocus: String = "New Focus"
var details: String? init(completed: Date? = nil, theFocus: String, details: String? = nil) {
self.completed = completed
self.theFocus = theFocus
self.details = details
}
}struct FocusItemDescriptors {
static let currentFocusPredicate = #Predicate<FocusItem> { $0.completed == nil } static let sortDescriptor = SortDescriptor(\FocusItem.created, order: .reverse)
static let currentFocusFetchDescriptor = FetchDescriptor(
predicate: currentFocusPredicate, sortBy: [sortDescriptor])
}
``````
import SwiftData
import SwiftUI
import WidgetKit struct ContentView: View {
@Query(
filter: FocusItemDescriptors.currentFocusPredicate,
sort: [FocusItemDescriptors.sortDescriptor]) private var items: [FocusItem]
@Environment(\.modelContext) private var modelContext @State private var isAddingNewItem = false
@State private var newFocusText = ""
var body: some View {
NavigationStack {
List {
ForEach(items) { item in
NavigationLink {
FocusItemDetailView(item: item)
} label: {
Text(item.theFocus)
}
}
.onDelete(perform: deleteItems)
}
.navigationTitle("Focus")
.toolbar {
#if os(iOS)
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
#endif
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}
.sheet(isPresented: $isAddingNewItem) {
AddFocusItemView(isPresented: $isAddingNewItem, addItem: addNewItemWithFocus)
}
}
private func addItem() {
isAddingNewItem = true
}
private func addNewItemWithFocus(_ focus: String) {
withAnimation {
let newItem = FocusItem(theFocus: focus)
modelContext.insert(newItem)
DataManager.shared.reloadWidgets()
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(items[index])
}
DataManager.shared.reloadWidgets()
}
}
}struct FocusItemDetailView: View {
@Environment(\.dismiss) private var dismiss
let item: FocusItem var body: some View {
VStack {
Text(item.theFocus)
if let details = item.details {
Text(details)
}
Text(
"\(item.created, format: Date.FormatStyle(date: .numeric, time: .standard))"
)
Button {
item.completed = Date()
DataManager.shared.reloadWidgets()
dismiss()
} label: {
Text("Mark as Complete")
}
}
}
}
struct AddFocusItemView: View {
@Binding var isPresented: Bool
let addItem: (String) -> Void
@State private var newFocusText = "" var body: some View {
NavigationView {
Form {
TextField("What is your focus?", text: $newFocusText, axis: .vertical)
.lineLimit(3...10)
}
.navigationTitle("New Focus")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") {
isPresented = false
}
}
ToolbarItem(placement: .confirmationAction) {
Button("Add") {
addItem(newFocusText)
isPresented = false
}
.disabled(newFocusText.isEmpty)
}
}
}
}
``` |