home: aviso visible de incumplimientos con acceso al detalle
El panel de avisos solo se alcanzaba desde el menu "..." de la barra, asi que los incumplimientos pasaban desapercibidos. Ahora, cuando la semana rompe reglas, aparece un banner bajo el selector de semana con el numero de comidas afectadas, un resumen de donde estan (Lun - Cena, Mie - Comida) y un boton Ver que abre el panel con la explicacion y el arreglo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013H6bXqGX1ygwib1Dm3n3UG
This commit is contained in:
@@ -317,11 +317,73 @@ struct HomeView: View {
|
||||
.padding(.bottom, 10)
|
||||
}
|
||||
|
||||
/// Banner shown on the home whenever the week breaks rules. The panel used
|
||||
/// to be reachable only from the "···" menu, so violations went unnoticed.
|
||||
@ViewBuilder
|
||||
private func violationsBanner(plan: WeekPlan) -> some View {
|
||||
let violations = AutocompleteEngine.findViolations(plan: plan, allDishes: dishes, allTags: tags)
|
||||
if !violations.isEmpty {
|
||||
Button {
|
||||
showViolationsPanel = true
|
||||
} label: {
|
||||
HStack(spacing: 10) {
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(.mealMoodWarning)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(String(format: String(localized: "violations_banner_title"), violations.count))
|
||||
.font(.mealMoodSmall.weight(.semibold))
|
||||
.foregroundColor(.mealMoodTextPrimary)
|
||||
Text(violationsSummary(violations))
|
||||
.font(.mealMoodCaption)
|
||||
.foregroundColor(.mealMoodTextSecondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("violations_banner_cta")
|
||||
.font(.mealMoodCaption.weight(.semibold))
|
||||
.foregroundColor(.white)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 5)
|
||||
.background(Color.mealMoodWarning)
|
||||
.clipShape(Capsule())
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 10)
|
||||
.background(Color.mealMoodWarning.opacity(0.12))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.stroke(Color.mealMoodWarning.opacity(0.45), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.bottom, 8)
|
||||
}
|
||||
}
|
||||
|
||||
/// "Lun · Cena, Mié · Comida" — where the problems are, at a glance.
|
||||
private func violationsSummary(_ violations: [AutocompleteEngine.RuleViolation]) -> String {
|
||||
let language = settings?.languageEnum.resolved() ?? .spanish
|
||||
let keys = ["day_mon","day_tue","day_wed","day_thu","day_fri","day_sat","day_sun"]
|
||||
return violations.prefix(3).map { violation in
|
||||
let day = violation.dayOfWeek >= 0 && violation.dayOfWeek < keys.count
|
||||
? localizedString(keys[violation.dayOfWeek], language: language) : ""
|
||||
return "\(day) · \(localizedString(violation.mealType, language: language))"
|
||||
}.joined(separator: ", ")
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func mainContent(plan: WeekPlan, settings: AppSettings) -> some View {
|
||||
VStack(spacing: 0) {
|
||||
weekSwitcher(settings: settings)
|
||||
|
||||
violationsBanner(plan: plan)
|
||||
|
||||
if showWeekLimitUpsell && !settings.isPremium {
|
||||
PremiumUpsellBanner(
|
||||
messageKey: "premium_limit_future_weeks",
|
||||
|
||||
Reference in New Issue
Block a user