2026-02-10 02:22:41 +00:00
|
|
|
import SwiftData
|
|
|
|
|
import SwiftUI
|
|
|
|
|
|
|
|
|
|
/// A preview modifier that provides sample task data for SwiftUI previews.
|
|
|
|
|
///
|
|
|
|
|
/// This modifier creates an in-memory SwiftData model container populated with representative sample todos across all task groups
|
|
|
|
|
/// (today, upcoming, overdue, completed).
|
|
|
|
|
/// It's designed to be used with SwiftUI previews to display realistic data without
|
|
|
|
|
/// requiring a persistent database.
|
|
|
|
|
///
|
|
|
|
|
/// ## Usage
|
|
|
|
|
/// Use the `.sampleTasks` trait on your preview:
|
|
|
|
|
///
|
|
|
|
|
/// ```swift
|
|
|
|
|
/// #Preview(traits: .sampleTasks) {
|
|
|
|
|
/// TaskGroupListView()
|
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// This automatically provides a model container with sample data to the preview.
|
|
|
|
|
struct SampleTaskDataModifier: PreviewModifier {
|
|
|
|
|
|
|
|
|
|
// MARK: Functions
|
|
|
|
|
|
|
|
|
|
/// Creates and configures a shared in-memory model container with sample task data.
|
|
|
|
|
///
|
|
|
|
|
/// This method is called once when the preview is loaded and creates an in-memory
|
|
|
|
|
/// SwiftData container populated with 8 representative todo tasks spanning all
|
|
|
|
|
/// task groups and various configurations.
|
|
|
|
|
///
|
|
|
|
|
/// - Returns: A `ModelContainer` configured for in-memory storage with sample data.
|
|
|
|
|
/// - Throws: An error if the model container cannot be created.
|
|
|
|
|
static func makeSharedContext() async throws -> ModelContainer {
|
|
|
|
|
let modelContainer = try ModelContainer(
|
|
|
|
|
for: Todo.self,
|
|
|
|
|
configurations: .init(isStoredInMemoryOnly: true)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
let calendar: Calendar = .current
|
|
|
|
|
|
|
|
|
|
let tasks: [Todo] = [
|
|
|
|
|
.init(
|
2026-02-10 15:31:52 +00:00
|
|
|
title: "Today task #1",
|
|
|
|
|
due: .now
|
2026-02-10 02:22:41 +00:00
|
|
|
),
|
|
|
|
|
.init(
|
2026-02-10 15:31:52 +00:00
|
|
|
title: "Today task #2",
|
2026-02-10 02:22:41 +00:00
|
|
|
note: "This is some random note attached to the task.",
|
2026-02-10 15:31:52 +00:00
|
|
|
due: .now
|
2026-02-10 02:22:41 +00:00
|
|
|
),
|
|
|
|
|
.init(
|
|
|
|
|
title: "Tomorrow task",
|
2026-02-10 15:31:52 +00:00
|
|
|
due: calendar.date(byAdding: .day, value: 1, to: .now) ?? .now
|
2026-02-10 02:22:41 +00:00
|
|
|
),
|
|
|
|
|
.init(
|
|
|
|
|
title: "Next week task",
|
|
|
|
|
note: "This is some random note attached to the task.",
|
2026-02-10 15:31:52 +00:00
|
|
|
due: calendar.date(byAdding: .day, value: 7, to: .now) ?? .now
|
2026-02-10 02:22:41 +00:00
|
|
|
),
|
|
|
|
|
.init(
|
|
|
|
|
title: "Yesterday task",
|
2026-02-10 15:31:52 +00:00
|
|
|
due: calendar.date(byAdding: .day, value: -1, to: .now) ?? .now
|
2026-02-10 02:22:41 +00:00
|
|
|
),
|
|
|
|
|
.init(
|
|
|
|
|
title: "Last week task",
|
|
|
|
|
note: "This is some random note attached to the task.",
|
2026-02-10 15:31:52 +00:00
|
|
|
due: calendar.date(byAdding: .day, value: -7, to: .now) ?? .now
|
2026-02-10 02:22:41 +00:00
|
|
|
),
|
|
|
|
|
.init(
|
2026-02-10 15:31:52 +00:00
|
|
|
title: "Completed task #1",
|
|
|
|
|
due: calendar.date(byAdding: .day, value: 1, to: .now) ?? .now,
|
|
|
|
|
completed: .now
|
2026-02-10 02:22:41 +00:00
|
|
|
),
|
|
|
|
|
.init(
|
2026-02-10 15:31:52 +00:00
|
|
|
title: "Completed task #2",
|
2026-02-10 02:22:41 +00:00
|
|
|
note: "This is some random note attached to the task.",
|
2026-02-10 15:31:52 +00:00
|
|
|
due: calendar.date(byAdding: .day, value: -1, to: .now) ?? .now,
|
|
|
|
|
completed: .now
|
2026-02-10 02:22:41 +00:00
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
for task in tasks {
|
|
|
|
|
modelContainer.mainContext.insert(task)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return modelContainer
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Applies the model container to the preview content.
|
|
|
|
|
///
|
|
|
|
|
/// This method is called by SwiftUI to apply the modifier to the preview.
|
|
|
|
|
/// It injects the model container into the SwiftUI environment, making it
|
|
|
|
|
/// available to any views that use `@Query` or `@Environment(\.modelContext)`.
|
|
|
|
|
///
|
|
|
|
|
/// - Parameters:
|
|
|
|
|
/// - content: The preview content to modify.
|
|
|
|
|
/// - context: The model container with sample data.
|
|
|
|
|
/// - Returns: The content with the model container applied.
|
|
|
|
|
func body(
|
|
|
|
|
content: Content,
|
|
|
|
|
context: ModelContainer
|
|
|
|
|
) -> some View {
|
|
|
|
|
content.modelContainer(context)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - PreviewTrait
|
|
|
|
|
|
|
|
|
|
extension PreviewTrait where T == Preview.ViewTraits {
|
|
|
|
|
|
|
|
|
|
/// A preview trait that provides sample task data.
|
|
|
|
|
///
|
|
|
|
|
/// Use this trait to automatically populate previews with realistic sample todos
|
|
|
|
|
/// without manually creating a model container and inserting data.
|
|
|
|
|
///
|
|
|
|
|
/// ## Example
|
|
|
|
|
/// ```swift
|
|
|
|
|
/// #Preview(traits: .sampleTasks) {
|
|
|
|
|
/// TaskGroupListView()
|
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// This is equivalent to manually creating a container with sample data but
|
|
|
|
|
/// much more concise and reusable across multiple previews.
|
|
|
|
|
static var sampleTasks: Self = .modifier(SampleTaskDataModifier())
|
|
|
|
|
|
|
|
|
|
}
|