1.2.1: surface "Copy previous week" on the empty-week banner
The exact-copy-from-previous-week action already existed but was buried in the magic-wand long-press context menu. Expose it as a visible secondary button on the auto-assign banner (shown only when the previous week actually has a menu), so users landing on a fresh week can one-tap copy last week's plan and then tweak it. Confirms before overwriting a week that already has dishes. - Extract requestCopyPreviousWeek() shared by the menu and the banner. - Add week_copied_previous analytics (copied_slots + source: empty_banner|menu). - Reuses the existing localized home_copy_previous_week string (all 6 languages). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
This commit is contained in:
@@ -23,6 +23,7 @@ struct HomeView: View {
|
||||
@State private var showWeekPicker: Bool = false
|
||||
@State private var weekPickerDate: Date = Date()
|
||||
@State private var showCopyPreviousConfirm: Bool = false
|
||||
@State private var copyPreviousSource: String = "menu"
|
||||
@State private var showReviewSentimentPrompt: Bool = false
|
||||
@State private var showReviewSupportPrompt: Bool = false
|
||||
@State private var showPostOnboardingAutoAssignPrompt: Bool = false
|
||||
@@ -149,11 +150,7 @@ struct HomeView: View {
|
||||
.disabled(!viewModel.canUndo(for: plan))
|
||||
|
||||
Button {
|
||||
if plan.slots.contains(where: { $0.dishId != nil }) {
|
||||
showCopyPreviousConfirm = true
|
||||
} else {
|
||||
copyFromPreviousWeek(currentPlan: plan, settings: settings)
|
||||
}
|
||||
requestCopyPreviousWeek(plan: plan, settings: settings, source: "menu")
|
||||
} label: {
|
||||
Label("home_copy_previous_week", systemImage: "doc.on.doc")
|
||||
}
|
||||
@@ -774,32 +771,53 @@ struct HomeView: View {
|
||||
|
||||
@ViewBuilder
|
||||
private func autoAssignBanner(emptyCount: Int, plan: WeekPlan, settings: AppSettings) -> some View {
|
||||
HStack(spacing: 12) {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("home_auto_assign_cta_title")
|
||||
.font(.mealMoodBodyBold)
|
||||
.foregroundColor(.mealMoodTextPrimary)
|
||||
Text(String(format: String(localized: "home_auto_assign_cta_slots"), emptyCount))
|
||||
.font(.mealMoodCaption)
|
||||
.foregroundColor(.mealMoodTextSecondary)
|
||||
}
|
||||
Spacer()
|
||||
Button {
|
||||
viewModel.autoComplete(plan: plan, dishes: dishes, tags: tags, settings: settings, allPlans: weekPlans)
|
||||
} label: {
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: "wand.and.stars")
|
||||
Text("home_auto_assign_cta_button")
|
||||
.font(.mealMoodSmall.weight(.semibold))
|
||||
VStack(spacing: 10) {
|
||||
HStack(spacing: 12) {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("home_auto_assign_cta_title")
|
||||
.font(.mealMoodBodyBold)
|
||||
.foregroundColor(.mealMoodTextPrimary)
|
||||
Text(String(format: String(localized: "home_auto_assign_cta_slots"), emptyCount))
|
||||
.font(.mealMoodCaption)
|
||||
.foregroundColor(.mealMoodTextSecondary)
|
||||
}
|
||||
.foregroundColor(.white)
|
||||
.padding(.horizontal, 14)
|
||||
.padding(.vertical, 8)
|
||||
.background(Color.mealMoodCoral)
|
||||
.clipShape(Capsule())
|
||||
Spacer()
|
||||
Button {
|
||||
viewModel.autoComplete(plan: plan, dishes: dishes, tags: tags, settings: settings, allPlans: weekPlans)
|
||||
} label: {
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: "wand.and.stars")
|
||||
Text("home_auto_assign_cta_button")
|
||||
.font(.mealMoodSmall.weight(.semibold))
|
||||
}
|
||||
.foregroundColor(.white)
|
||||
.padding(.horizontal, 14)
|
||||
.padding(.vertical, 8)
|
||||
.background(Color.mealMoodCoral)
|
||||
.clipShape(Capsule())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(viewModel.isAutoCompleting)
|
||||
}
|
||||
|
||||
if previousWeekHasMenu() {
|
||||
Button {
|
||||
requestCopyPreviousWeek(plan: plan, settings: settings, source: "empty_banner")
|
||||
} label: {
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: "doc.on.doc")
|
||||
Text("home_copy_previous_week")
|
||||
.font(.mealMoodSmall.weight(.semibold))
|
||||
}
|
||||
.foregroundColor(.mealMoodCoral)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 8)
|
||||
.background(Capsule().fill(Color.white.opacity(0.75)))
|
||||
.overlay(Capsule().stroke(Color.mealMoodCoral.opacity(0.4), lineWidth: 1))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(viewModel.isAutoCompleting)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(viewModel.isAutoCompleting)
|
||||
}
|
||||
.padding(12)
|
||||
.background(
|
||||
@@ -869,6 +887,22 @@ struct HomeView: View {
|
||||
.padding(.horizontal, 16)
|
||||
}
|
||||
|
||||
private func previousWeekHasMenu() -> Bool {
|
||||
guard let previous = fetchWeekPlan(for: viewModel.currentWeekStart.addingDays(-7)) else { return false }
|
||||
return previous.slots.contains { $0.dishId != nil }
|
||||
}
|
||||
|
||||
/// Copies the previous week, asking to confirm first only when the current
|
||||
/// week already has dishes that would be overwritten.
|
||||
private func requestCopyPreviousWeek(plan: WeekPlan, settings: AppSettings, source: String) {
|
||||
copyPreviousSource = source
|
||||
if plan.slots.contains(where: { $0.dishId != nil }) {
|
||||
showCopyPreviousConfirm = true
|
||||
} else {
|
||||
copyFromPreviousWeek(currentPlan: plan, settings: settings)
|
||||
}
|
||||
}
|
||||
|
||||
private func copyFromPreviousWeek(currentPlan: WeekPlan, settings: AppSettings) {
|
||||
let previousPlan = fetchWeekPlan(for: viewModel.currentWeekStart.addingDays(-7))
|
||||
viewModel.copyFromPreviousWeek(
|
||||
@@ -876,7 +910,8 @@ struct HomeView: View {
|
||||
previousPlan: previousPlan,
|
||||
settings: settings,
|
||||
allTags: tags,
|
||||
allDishes: dishes
|
||||
allDishes: dishes,
|
||||
source: copyPreviousSource
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user