From 7b982799dbb39b02191be3896edc517c9f37fafb Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Tue, 10 Feb 2026 01:22:11 +0100 Subject: [PATCH] Implemented the SampleTaskDataModifier preview modifier in the app target. --- .../Modifiers/SampleTaskDataModifier.swift | 131 ++++++++++++++++++ Todos.xcodeproj/project.pbxproj | 2 + 2 files changed, 133 insertions(+) create mode 100644 App/Previews/Modifiers/SampleTaskDataModifier.swift diff --git a/App/Previews/Modifiers/SampleTaskDataModifier.swift b/App/Previews/Modifiers/SampleTaskDataModifier.swift new file mode 100644 index 0000000..5b463ef --- /dev/null +++ b/App/Previews/Modifiers/SampleTaskDataModifier.swift @@ -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()) + +} diff --git a/Todos.xcodeproj/project.pbxproj b/Todos.xcodeproj/project.pbxproj index da9cfef..3688d17 100644 --- a/Todos.xcodeproj/project.pbxproj +++ b/Todos.xcodeproj/project.pbxproj @@ -378,6 +378,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = App/Previews/Modifiers/SampleTaskDataModifier.swift; DEVELOPMENT_TEAM = 7FMNM89WKG; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; @@ -423,6 +424,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = App/Previews/Modifiers/SampleTaskDataModifier.swift; DEVELOPMENT_TEAM = 7FMNM89WKG; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES;