Group tasks feature #3

Merged
javier merged 7 commits from app/group-tasks into main 2026-02-10 02:22:41 +00:00
2 changed files with 133 additions and 0 deletions
Showing only changes of commit 7b982799db - Show all commits
@@ -0,0 +1,131 @@
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 today: Date = .now
let tomorrow: Date = calendar.date(byAdding: .day, value: 1, to: today) ?? today
let yesterday = calendar.date(byAdding: .day, value: -1, to: today) ?? today
let tasks: [Todo] = [
.init(
title: "Today task 1",
due: today
),
.init(
title: "Today task 2",
note: "This is some random note attached to the task.",
due: today
),
.init(
title: "Tomorrow task",
due: tomorrow
),
.init(
title: "Next week task",
note: "This is some random note attached to the task.",
due: calendar.date(byAdding: .day, value: 7, to: today) ?? today
),
.init(
title: "Yesterday task",
due: yesterday
),
.init(
title: "Last week task",
note: "This is some random note attached to the task.",
due: calendar.date(byAdding: .day, value: -7, to: today) ?? today
),
.init(
title: "Completed task 1",
due: today,
completed: today
),
.init(
title: "Completed task 2",
note: "This is some random note attached to the task.",
due: yesterday,
completed: today
),
]
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())
}
+2
View File
@@ -378,6 +378,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = App/Previews/Modifiers/SampleTaskDataModifier.swift;
DEVELOPMENT_TEAM = 7FMNM89WKG; DEVELOPMENT_TEAM = 7FMNM89WKG;
ENABLE_APP_SANDBOX = YES; ENABLE_APP_SANDBOX = YES;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@@ -423,6 +424,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = App/Previews/Modifiers/SampleTaskDataModifier.swift;
DEVELOPMENT_TEAM = 7FMNM89WKG; DEVELOPMENT_TEAM = 7FMNM89WKG;
ENABLE_APP_SANDBOX = YES; ENABLE_APP_SANDBOX = YES;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;