// // HomeView.swift // Shared // // Created by Trey Tartt on 1/5/22. // import SwiftUI import SwiftData struct DayViewConstants { static let maxHeaderHeight = 200.0 static let minHeaderHeight = 120.0 } struct DayView: View { @AppStorage(UserDefaultsStore.Keys.deleteEnable.rawValue, store: GroupUserDefaults.groupDefaults) private var deleteEnabled = true @AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system @AppStorage(UserDefaultsStore.Keys.moodImages.rawValue, store: GroupUserDefaults.groupDefaults) private var imagePack: MoodImages = .FontAwesome @AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default @AppStorage(UserDefaultsStore.Keys.dayViewStyle.rawValue, store: GroupUserDefaults.groupDefaults) private var dayViewStyle: DayViewStyle = .classic @Environment(\.colorScheme) private var colorScheme // MARK: edit row properties @State private var showingSheet = false @State private var selectedEntry: MoodEntryModel? // // MARK: ?? properties @State private var showTodayInput = true @StateObject private var onboardingData = OnboardingDataDataManager.shared @StateObject private var filteredDays = DaysFilterClass.shared @EnvironmentObject var iapManager: IAPManager @ObservedObject var viewModel: DayViewViewModel var body: some View { ZStack { mainView .onAppear(perform: { AnalyticsManager.shared.trackScreen(.day) }) .sheet(isPresented: $showingSheet) { SettingsView() } .sheet(item: $selectedEntry) { entry in EntryDetailView( entry: entry, onMoodUpdate: { newMood in viewModel.update(entry: entry, toMood: newMood) }, onDelete: { viewModel.update(entry: entry, toMood: .missing) } ) } } .padding([.top]) .preferredColorScheme(theme.preferredColorScheme) } // MARK: Views public var mainView: some View { VStack(spacing: 12) { if viewModel.hasNoData { Spacer() EmptyHomeView(showVote: true, viewModel: viewModel) Spacer() } else { headerView listView } } .padding([.leading, .trailing]) .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in viewModel.updateData() } .background( theme.currentTheme.bg ) } private var headerView: some View { VStack { if ShowBasedOnVoteLogics.isMissingCurrentVote(onboardingData: UserDefaultsStore.getOnboarding()) { AddMoodHeaderView(addItemHeaderClosure: { (mood, date) in viewModel.add(mood: mood, forDate: date, entryType: .header) }) .widgetVotingTip() } } } /// Sorted year/month data cached in ViewModel — avoids re-sorting on every render private var sortedGroupedData: [(year: Int, months: [(month: Int, entries: [MoodEntryModel])])] { viewModel.sortedGroupedData } private var listView: some View { ScrollView { LazyVStack(spacing: 8, pinnedViews: [.sectionHeaders]) { ForEach(sortedGroupedData, id: \.year) { yearData in ForEach(yearData.months, id: \.month) { monthData in Section(header: SectionHeaderView(month: monthData.month, year: yearData.year, entries: monthData.entries)) { monthListView(month: monthData.month, year: yearData.year, entries: monthData.entries) } } } } .padding(.bottom, 20) } .background( theme.currentTheme.secondaryBGColor ) .cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight]) } } // view that make up the list body extension DayView { private func SectionHeaderView(month: Int, year: Int, entries: [MoodEntryModel]) -> some View { Group { switch dayViewStyle { case .aura: auraSectionHeader(month: month, year: year) case .chronicle: chronicleSectionHeader(month: month, year: year) case .neon: neonSectionHeader(month: month, year: year) case .ink: inkSectionHeader(month: month, year: year) case .prism: prismSectionHeader(month: month, year: year) case .tape: tapeSectionHeader(month: month, year: year) case .morph: morphSectionHeader(month: month, year: year) case .stack: stackSectionHeader(month: month, year: year) case .wave: waveSectionHeader(month: month, year: year, entries: entries) case .pattern: patternSectionHeader(month: month, year: year) case .leather: leatherSectionHeader(month: month, year: year) case .glass: glassSectionHeader(month: month, year: year) case .motion: motionSectionHeader(month: month, year: year) case .micro: microSectionHeader(month: month, year: year) default: defaultSectionHeader(month: month, year: year) } } .accessibilityIdentifier(AccessibilityID.DaySection.header(month: month, year: year)) } private func defaultSectionHeader(month: Int, year: Int) -> some View { HStack(spacing: 10) { // Calendar icon Image(systemName: "calendar") .font(.body.weight(.semibold)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.6)) .accessibilityHidden(true) Text("\(Random.monthName(fromMonthInt: month)) \(String(year))") .font(.title3.weight(.bold)) .foregroundColor(theme.currentTheme.labelColor) Spacer() } .padding(.horizontal, 16) .padding(.vertical, 14) .background(.ultraThinMaterial) .accessibilityElement(children: .combine) .accessibilityLabel(String(localized: "\(Random.monthName(fromMonthInt: month)) \(String(year))")) .accessibilityAddTraits(.isHeader) } private func auraSectionHeader(month: Int, year: Int) -> some View { HStack(spacing: 0) { // Large month number as hero element Text(String(format: "%02d", month)) .font(.largeTitle.weight(.black)) .foregroundStyle( LinearGradient( colors: [theme.currentTheme.labelColor, theme.currentTheme.labelColor.opacity(0.4)], startPoint: .top, endPoint: .bottom ) ) .frame(width: 80) VStack(alignment: .leading, spacing: 2) { Text(Random.monthName(fromMonthInt: month).uppercased()) .font(.subheadline.weight(.bold)) .tracking(3) .foregroundColor(theme.currentTheme.labelColor) Text(String(year)) .font(.caption.weight(.medium)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.5)) } Spacer() // Decorative element Circle() .fill(theme.currentTheme.labelColor.opacity(0.1)) .frame(width: 8, height: 8) } .padding(.horizontal, 20) .padding(.vertical, 20) .background( ZStack { // Base material Rectangle() .fill(.ultraThinMaterial) // Subtle gradient accent LinearGradient( colors: [ theme.currentTheme.labelColor.opacity(0.03), Color.clear ], startPoint: .leading, endPoint: .trailing ) } ) } private func chronicleSectionHeader(month: Int, year: Int) -> some View { VStack(alignment: .leading, spacing: 0) { // Thick editorial rule Rectangle() .fill(theme.currentTheme.labelColor) .frame(height: 4) HStack(alignment: .firstTextBaseline, spacing: 12) { // Large serif month name Text(Random.monthName(fromMonthInt: month).uppercased()) .font(.title.weight(.regular)) .foregroundColor(theme.currentTheme.labelColor) // Year in lighter weight Text(String(year)) .font(.body.weight(.light)) .italic() .foregroundColor(theme.currentTheme.labelColor.opacity(0.5)) Spacer() // Decorative flourish Text("§") .font(.title3.weight(.regular)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.3)) } .padding(.horizontal, 16) .padding(.vertical, 16) // Thin bottom rule Rectangle() .fill(theme.currentTheme.labelColor.opacity(0.2)) .frame(height: 1) } .background(.ultraThinMaterial) } private func neonSectionHeader(month: Int, year: Int) -> some View { HStack(spacing: 12) { // Glowing terminal prompt Text(">") .font(.headline.weight(.bold).monospaced()) .foregroundColor(Color(red: 0.4, green: 1.0, blue: 0.4)) .shadow(color: Color(red: 0.4, green: 1.0, blue: 0.4).opacity(0.8), radius: 4, x: 0, y: 0) Text("\(Random.monthName(fromMonthInt: month).uppercased())_\(String(year))") .font(.body.weight(.bold).monospaced()) .foregroundColor(.white) .shadow(color: .white.opacity(0.3), radius: 2, x: 0, y: 0) Spacer() // Blinking cursor effect Rectangle() .fill(Color(red: 0.4, green: 1.0, blue: 0.4)) .frame(width: 10, height: 18) .shadow(color: Color(red: 0.4, green: 1.0, blue: 0.4), radius: 4, x: 0, y: 0) } .padding(.horizontal, 20) .padding(.vertical, 16) .background( ZStack { Color.black // Scanlines - simplified with Canvas for performance Canvas { context, size in let lineHeight: CGFloat = 4 var y: CGFloat = 0 while y < size.height { let rect = CGRect(x: 0, y: y, width: size.width, height: 1) context.fill(Path(rect), with: .color(.white.opacity(0.02))) y += lineHeight } } } ) .accessibilityIgnoresInvertColors(true) } private func inkSectionHeader(month: Int, year: Int) -> some View { HStack(alignment: .center, spacing: 16) { // Brush stroke accent Capsule() .fill(theme.currentTheme.labelColor.opacity(0.15)) .frame(width: 40, height: 3) VStack(alignment: .leading, spacing: 2) { Text(Random.monthName(fromMonthInt: month)) .font(.headline.weight(.thin)) .tracking(4) .foregroundColor(theme.currentTheme.labelColor) Text(String(year)) .font(.caption2.weight(.ultraLight)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.4)) } Spacer() // Zen circle ornament Circle() .trim(from: 0, to: 0.7) .stroke(theme.currentTheme.labelColor.opacity(0.2), style: StrokeStyle(lineWidth: 2, lineCap: .round)) .frame(width: 20, height: 20) .rotationEffect(.degrees(-60)) } .padding(.horizontal, 24) .padding(.vertical, 20) .background( Rectangle() .fill(.ultraThinMaterial) ) } private func prismSectionHeader(month: Int, year: Int) -> some View { ZStack { // Rainbow edge glow RoundedRectangle(cornerRadius: 16) .fill( AngularGradient( colors: [.red, .orange, .yellow, .green, .blue, .purple, .red], center: .leading ) ) .blur(radius: 8) .opacity(0.3) // Glass content HStack(spacing: 12) { Text(Random.monthName(fromMonthInt: month)) .font(.title3.weight(.semibold)) .foregroundColor(theme.currentTheme.labelColor) Capsule() .fill(theme.currentTheme.labelColor.opacity(0.2)) .frame(width: 4, height: 4) Text(String(year)) .font(.body.weight(.medium)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.6)) Spacer() } .padding(.horizontal, 20) .padding(.vertical, 16) .background(.ultraThinMaterial) .clipShape(RoundedRectangle(cornerRadius: 16)) } } private func tapeSectionHeader(month: Int, year: Int) -> some View { HStack(spacing: 12) { // Tape reel icon ZStack { Circle() .stroke(theme.currentTheme.labelColor.opacity(0.3), lineWidth: 2) .frame(width: 24, height: 24) Circle() .fill(theme.currentTheme.labelColor.opacity(0.2)) .frame(width: 10, height: 10) } VStack(alignment: .leading, spacing: 2) { Text("SIDE A") .font(.caption2.weight(.bold).monospaced()) .foregroundColor(theme.currentTheme.labelColor.opacity(0.4)) Text("\(Random.monthName(fromMonthInt: month).uppercased()) '\(String(year).suffix(2))") .font(.body.weight(.black)) .foregroundColor(theme.currentTheme.labelColor) .tracking(1) } Spacer() // Track counter Text(String(format: "%02d", month)) .font(.title3.weight(.bold).monospaced()) .foregroundColor(theme.currentTheme.labelColor.opacity(0.3)) } .padding(.horizontal, 16) .padding(.vertical, 14) .background( RoundedRectangle(cornerRadius: 8) .fill(.ultraThinMaterial) ) } private func morphSectionHeader(month: Int, year: Int) -> some View { ZStack { // Organic blob background HStack { Ellipse() .fill(theme.currentTheme.labelColor.opacity(0.08)) .frame(width: 120, height: 60) .blur(radius: 15) .offset(x: -20) Spacer() } HStack(spacing: 16) { Text(Random.monthName(fromMonthInt: month)) .font(.title2.weight(.light)) .foregroundColor(theme.currentTheme.labelColor) Text(String(year)) .font(.subheadline.weight(.regular)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.4)) Spacer() // Blob indicator Circle() .fill(theme.currentTheme.labelColor.opacity(0.15)) .frame(width: 12, height: 12) .blur(radius: 2) } .padding(.horizontal, 24) .padding(.vertical, 18) } .background(.ultraThinMaterial) } private func stackSectionHeader(month: Int, year: Int) -> some View { VStack(alignment: .leading, spacing: 0) { // Torn edge - simplified with Canvas for performance Canvas { context, size in let segmentWidth = size.width / 15 for i in 0..<15 { let height = CGFloat(2 + (i * 5) % 3) // Deterministic pseudo-random heights let rect = CGRect(x: CGFloat(i) * segmentWidth, y: 0, width: segmentWidth, height: height) context.fill(Path(rect), with: .color(Color(uiColor: UIColor.label).opacity(0.2))) } } .frame(height: 4) HStack(spacing: 12) { // Red margin line Rectangle() .fill(Color.red.opacity(0.3)) .frame(width: 2) Text(Random.monthName(fromMonthInt: month)) .font(.headline.weight(.regular)) .foregroundColor(theme.currentTheme.labelColor) Text(String(year)) .font(.subheadline.weight(.light)) .italic() .foregroundColor(theme.currentTheme.labelColor.opacity(0.5)) Spacer() } .padding(.horizontal, 16) .padding(.vertical, 14) } .background(.ultraThinMaterial) } private func waveSectionHeader(month: Int, year: Int, entries: [MoodEntryModel]) -> some View { // Calculate average mood (excluding missing entries) let validEntries = entries.filter { $0.moodValue != Mood.missing.rawValue && $0.moodValue <= 4 } let averageMood: Double = validEntries.isEmpty ? 0 : Double(validEntries.map { $0.moodValue }.reduce(0, +)) / Double(validEntries.count) let hasData = !validEntries.isEmpty // Map average to a mood for coloring (0-4 scale) let moodForColor: Mood = { if !hasData { return .missing } switch Int(round(averageMood)) { case 0: return .horrible case 1: return .bad case 2: return .average case 3: return .good default: return .great } }() let barColor = hasData ? moodTint.color(forMood: moodForColor) : theme.currentTheme.labelColor.opacity(0.2) // Width percentage based on average (0=20%, 4=100%) let widthPercent = hasData ? 0.2 + (averageMood / 4.0) * 0.8 : 0.2 return HStack(spacing: 0) { // Month number Text(String(format: "%02d", month)) .font(.title.weight(.thin)) .foregroundColor(hasData ? barColor.opacity(0.6) : theme.currentTheme.labelColor.opacity(0.3)) .frame(width: 50) // Gradient bar sized by average mood GeometryReader { geo in ZStack(alignment: .leading) { // Background track Capsule() .fill(theme.currentTheme.labelColor.opacity(0.1)) .frame(height: 8) // Colored bar based on average Capsule() .fill( LinearGradient( colors: [barColor, barColor.opacity(0.6)], startPoint: .leading, endPoint: .trailing ) ) .frame(width: geo.size.width * widthPercent, height: 8) .shadow(color: barColor.opacity(0.4), radius: 4, x: 0, y: 2) } } .frame(height: 8) .padding(.horizontal, 12) VStack(alignment: .trailing, spacing: 2) { Text(Random.monthName(fromMonthInt: month)) .font(.subheadline.weight(.medium)) .foregroundColor(theme.currentTheme.labelColor) if hasData { Text(String(format: "%.1f avg", averageMood + 1)) // Display as 1-5 .font(.caption2.weight(.semibold)) .foregroundColor(barColor) } else { Text(String(year)) .font(.caption2.weight(.regular)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.4)) } } } .padding(.horizontal, 16) .padding(.vertical, 16) .background(.ultraThinMaterial) } private func patternSectionHeader(month: Int, year: Int) -> some View { HStack(spacing: 10) { Image(systemName: "calendar") .font(.body.weight(.semibold)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.6)) Text("\(Random.monthName(fromMonthInt: month)) \(String(year))") .font(.title3.weight(.bold)) .foregroundColor(theme.currentTheme.labelColor) Spacer() } .padding(.horizontal, 16) .padding(.vertical, 14) .background(.ultraThinMaterial) } private func leatherSectionHeader(month: Int, year: Int) -> some View { ZStack { // Leather texture background RoundedRectangle(cornerRadius: 4) .fill( LinearGradient( colors: [ Color(red: 0.45, green: 0.28, blue: 0.18), Color(red: 0.38, green: 0.22, blue: 0.12), Color(red: 0.42, green: 0.25, blue: 0.15) ], startPoint: .top, endPoint: .bottom ) ) // Leather grain texture Rectangle() .fill( EllipticalGradient( colors: [.white.opacity(0.08), .clear], center: .topLeading, startRadiusFraction: 0, endRadiusFraction: 0.5 ) ) HStack { // Left stitching VStack(spacing: 6) { ForEach(0..<4, id: \.self) { _ in Capsule() .fill(Color(red: 0.7, green: 0.55, blue: 0.35)) .frame(width: 6, height: 2) } } .padding(.leading, 8) VStack(alignment: .leading, spacing: 2) { Text(Random.monthName(fromMonthInt: month).uppercased()) .font(.body.weight(.bold)) .foregroundColor(Color(red: 0.9, green: 0.85, blue: 0.75)) .shadow(color: .black.opacity(0.3), radius: 1, x: 0, y: 1) Text(String(year)) .font(.caption.weight(.medium)) .foregroundColor(Color(red: 0.8, green: 0.7, blue: 0.55)) } .padding(.leading, 12) Spacer() // Metal rivet ZStack { Circle() .fill( RadialGradient( colors: [ Color(red: 0.85, green: 0.75, blue: 0.5), Color(red: 0.55, green: 0.45, blue: 0.25) ], center: .topLeading, startRadius: 0, endRadius: 10 ) ) .frame(width: 16, height: 16) Circle() .fill(Color(red: 0.4, green: 0.3, blue: 0.2)) .frame(width: 6, height: 6) } .padding(.trailing, 16) } .padding(.vertical, 14) } .frame(height: 56) .clipShape(RoundedRectangle(cornerRadius: 4)) } private func glassSectionHeader(month: Int, year: Int) -> some View { ZStack { // Variable blur glass layers RoundedRectangle(cornerRadius: 20) .fill(.ultraThinMaterial) // Light refraction effect GeometryReader { geo in Ellipse() .fill( LinearGradient( colors: [.white.opacity(0.4), .white.opacity(0)], startPoint: .topLeading, endPoint: .bottomTrailing ) ) .frame(width: geo.size.width * 0.6, height: 30) .blur(radius: 10) .offset(x: 20, y: 5) } // Rainbow edge shimmer RoundedRectangle(cornerRadius: 20) .stroke( AngularGradient( colors: [ .white.opacity(0.5), .blue.opacity(0.2), .purple.opacity(0.2), .white.opacity(0.3), .white.opacity(0.5) ], center: .center ), lineWidth: 1 ) .blur(radius: 0.5) HStack(spacing: 16) { // Floating glass orb ZStack { Circle() .fill(.ultraThinMaterial) .frame(width: 36, height: 36) Circle() .fill( LinearGradient( colors: [.white.opacity(0.6), .clear], startPoint: .topLeading, endPoint: .bottomTrailing ) ) .frame(width: 34, height: 34) .blur(radius: 4) Text(String(format: "%02d", month)) .font(.subheadline.weight(.semibold)) .foregroundColor(theme.currentTheme.labelColor) } VStack(alignment: .leading, spacing: 2) { Text(Random.monthName(fromMonthInt: month)) .font(.headline.weight(.medium)) .foregroundColor(theme.currentTheme.labelColor) Text(String(year)) .font(.caption.weight(.regular)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.5)) } Spacer() // Specular highlight dot Circle() .fill(.white.opacity(0.6)) .frame(width: 6, height: 6) .blur(radius: 1) } .padding(.horizontal, 20) } .frame(height: 64) } // MARK: - Motion Style Section Header private func motionSectionHeader(month: Int, year: Int) -> some View { ZStack { // Animated gradient background RoundedRectangle(cornerRadius: 18) .fill( LinearGradient( colors: [ Color.blue.opacity(0.15), Color.purple.opacity(0.1), Color.pink.opacity(0.1) ], startPoint: .topLeading, endPoint: .bottomTrailing ) ) // Floating orbs GeometryReader { geo in Circle() .fill( RadialGradient( colors: [Color.blue.opacity(0.3), Color.clear], center: .center, startRadius: 0, endRadius: 30 ) ) .frame(width: 60, height: 60) .offset(x: geo.size.width * 0.7, y: -10) Circle() .fill( RadialGradient( colors: [Color.purple.opacity(0.25), Color.clear], center: .center, startRadius: 0, endRadius: 20 ) ) .frame(width: 40, height: 40) .offset(x: 30, y: geo.size.height * 0.5) } HStack(spacing: 16) { // Motion icon ZStack { Circle() .fill( LinearGradient( colors: [Color.blue.opacity(0.5), Color.purple.opacity(0.5)], startPoint: .topLeading, endPoint: .bottomTrailing ) ) .frame(width: 44, height: 44) Image(systemName: "gyroscope") .font(.title2.weight(.medium)) .foregroundColor(.white) } .shadow(color: Color.purple.opacity(0.3), radius: 8, x: 0, y: 4) VStack(alignment: .leading, spacing: 2) { Text(Random.monthName(fromMonthInt: month)) .font(.title3.weight(.semibold)) .foregroundColor(theme.currentTheme.labelColor) Text(String(year)) .font(.caption.weight(.medium)) .foregroundColor(theme.currentTheme.labelColor.opacity(0.5)) } Spacer() // Tilt indicator Image(systemName: "iphone.gen3.radiowaves.left.and.right") .font(.headline) .foregroundColor(theme.currentTheme.labelColor.opacity(0.3)) } .padding(.horizontal, 18) } .frame(height: 68) .clipShape(RoundedRectangle(cornerRadius: 18)) .overlay( RoundedRectangle(cornerRadius: 18) .stroke(Color.white.opacity(0.3), lineWidth: 1) ) } // MARK: - Micro Style Section Header private func microSectionHeader(month: Int, year: Int) -> some View { HStack(spacing: 8) { // Minimal colored bar RoundedRectangle(cornerRadius: 2) .fill(theme.currentTheme.labelColor.opacity(0.3)) .frame(width: 3, height: 16) Text("\(Random.monthName(fromMonthInt: month).prefix(3).uppercased())") .font(.caption2.weight(.bold).monospaced()) .foregroundColor(theme.currentTheme.labelColor.opacity(0.6)) Text("•") .font(.caption2) .foregroundColor(theme.currentTheme.labelColor.opacity(0.3)) Text(String(year)) .font(.caption2.weight(.medium).monospaced()) .foregroundColor(theme.currentTheme.labelColor.opacity(0.4)) // Thin separator line Rectangle() .fill(theme.currentTheme.labelColor.opacity(0.1)) .frame(height: 1) } .padding(.horizontal, 14) .padding(.vertical, 8) } private var gridColumns: [GridItem] { [ GridItem(.flexible(), spacing: 10), GridItem(.flexible(), spacing: 10), GridItem(.flexible(), spacing: 10) ] } @ViewBuilder private func monthListView(month: Int, year: Int, entries: [MoodEntryModel]) -> some View { let filteredEntries = entries.sorted(by: { $0.forDate > $1.forDate }) .filter { filteredDays.currentFilters.contains($0.weekDay) } if dayViewStyle.isGridLayout { // Grid layout - 3 per row LazyVGrid(columns: gridColumns, spacing: 10) { ForEach(filteredEntries, id: \.self) { entry in EntryListView(entry: entry) .contentShape(Rectangle()) .onTapGesture { selectedEntry = entry } } } .padding(.horizontal, 12) .padding(.top, 8) } else { // Standard vertical layout VStack(spacing: 12) { ForEach(filteredEntries, id: \.self) { entry in EntryListView(entry: entry) .contentShape(Rectangle()) .onTapGesture { selectedEntry = entry } } } .padding(.horizontal, 12) .padding(.top, 8) } } } struct ViewOffsetKey: PreferenceKey { typealias Value = CGFloat static var defaultValue = CGFloat.zero static func reduce(value: inout Value, nextValue: () -> Value) { value += nextValue() } } struct DayView_Previews: PreviewProvider { static var previews: some View { DayView(viewModel: DayViewViewModel(addMonthStartWeekdayPadding: false)) .modelContainer(DataController.shared.container) .onAppear(perform: { DataController.shared.populateMemory() }) DayView(viewModel: DayViewViewModel(addMonthStartWeekdayPadding: false)) .preferredColorScheme(.dark) .modelContainer(DataController.shared.container) } }