// // AddToMealPlanSheet.swift // Nextcloud Cookbook iOS Client // import Foundation import SwiftUI struct AddToMealPlanSheet: View { @EnvironmentObject var mealPlan: MealPlanManager @Environment(\.dismiss) private var dismiss let recipeId: String let recipeName: String let prepTime: String? let recipeImage: UIImage? @State private var weekOffset: Int = 0 @State private var selectedDays: Set = [] private var calendar: Calendar { Calendar.current } private var weekDates: [Date] { let today = calendar.startOfDay(for: Date()) let weekday = calendar.component(.weekday, from: today) let daysToMonday = (weekday + 5) % 7 guard let monday = calendar.date(byAdding: .day, value: -daysToMonday, to: today), let offsetMonday = calendar.date(byAdding: .weekOfYear, value: weekOffset, to: monday) else { return [] } return (0..<7).compactMap { calendar.date(byAdding: .day, value: $0, to: offsetMonday) } } private var weekLabel: String { if weekOffset == 0 { return String(localized: "This Week") } else if weekOffset == 1 { return String(localized: "Next Week") } else if weekOffset == -1 { return String(localized: "Last Week") } else { return weekRangeString } } private var weekRangeString: String { guard let first = weekDates.first, let last = weekDates.last else { return "" } let formatter = DateFormatter() formatter.dateFormat = "dd.MM." return "\(formatter.string(from: first)) – \(formatter.string(from: last))" } var body: some View { NavigationStack { VStack(spacing: 0) { // Recipe header recipeHeader .padding() Divider() // Week navigation weekNavigationHeader .padding(.horizontal) .padding(.vertical, 8) // Day rows with checkboxes List { ForEach(weekDates, id: \.self) { date in let dayStr = MealPlanDate.dayString(from: date) let isAlreadyAssigned = mealPlan.isRecipeAssigned(recipeId, on: date) let existingCount = mealPlan.entries(for: date).count Button { if !isAlreadyAssigned { if selectedDays.contains(dayStr) { selectedDays.remove(dayStr) } else { selectedDays.insert(dayStr) } } } label: { HStack { Image(systemName: (isAlreadyAssigned || selectedDays.contains(dayStr)) ? "checkmark.circle.fill" : "circle") .foregroundStyle(isAlreadyAssigned ? Color.secondary : Color.nextcloudBlue) Text(dayDisplayName(date)) .foregroundStyle(isAlreadyAssigned ? .secondary : .primary) Spacer() if existingCount > 0 { Text("\(existingCount)") .font(.caption) .foregroundStyle(.secondary) .padding(.horizontal, 8) .padding(.vertical, 2) .background(Capsule().fill(Color(.tertiarySystemFill))) } } } .disabled(isAlreadyAssigned) } } .listStyle(.plain) } .navigationTitle("Schedule Recipe") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { dismiss() } } ToolbarItem(placement: .confirmationAction) { Button("Done") { let dates = selectedDays.compactMap { MealPlanDate.dateFromDay($0) } if !dates.isEmpty { mealPlan.assignRecipe(recipeId: recipeId, recipeName: recipeName, toDates: dates) } dismiss() } .disabled(selectedDays.isEmpty) } } } } private var recipeHeader: some View { HStack(spacing: 12) { if let recipeImage { Image(uiImage: recipeImage) .resizable() .aspectRatio(contentMode: .fill) .frame(width: 60, height: 60) .clipShape(RoundedRectangle(cornerRadius: 10)) } else { LinearGradient( gradient: Gradient(colors: [.ncGradientDark, .ncGradientLight]), startPoint: .topLeading, endPoint: .bottomTrailing ) .frame(width: 60, height: 60) .overlay { Image(systemName: "fork.knife") .foregroundStyle(.white.opacity(0.7)) } .clipShape(RoundedRectangle(cornerRadius: 10)) } VStack(alignment: .leading, spacing: 4) { Text(recipeName) .font(.headline) .lineLimit(2) if let prepTime, !prepTime.isEmpty { let duration = DurationComponents.fromPTString(prepTime) if duration.hourComponent > 0 || duration.minuteComponent > 0 { HStack(spacing: 4) { Image(systemName: "clock") .font(.caption) Text(duration.displayString) .font(.caption) } .foregroundStyle(.secondary) } } } Spacer() } } private var weekNavigationHeader: some View { HStack { Button { withAnimation { weekOffset -= 1 } } label: { Image(systemName: "chevron.left") .font(.title3) .foregroundStyle(Color.nextcloudBlue) } Spacer() VStack(spacing: 2) { Text(weekLabel) .font(.headline) if weekOffset == 0 || weekOffset == 1 || weekOffset == -1 { Text(weekRangeString) .font(.caption) .foregroundStyle(.secondary) } } Spacer() Button { withAnimation { weekOffset += 1 } } label: { Image(systemName: "chevron.right") .font(.title3) .foregroundStyle(Color.nextcloudBlue) } } } private func dayDisplayName(_ date: Date) -> String { let formatter = DateFormatter() formatter.dateFormat = "EEEE, d MMM" let name = formatter.string(from: date) if calendar.isDateInToday(date) { return "\(name) (\(String(localized: "Today")))" } return name } }