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:
@@ -460,3 +460,5 @@
|
||||
"violations_replace" = "Gericht ändern";
|
||||
"stats_tag_by_meal_title" = "Tags nach Mahlzeit";
|
||||
"stats_dishes_per_tag_title" = "Gerichte pro Tag";
|
||||
"violations_banner_title" = "%d Mahlzeit(en) verletzen deine Regeln";
|
||||
"violations_banner_cta" = "Ansehen";
|
||||
|
||||
@@ -460,3 +460,5 @@
|
||||
"violations_replace" = "Change dish";
|
||||
"stats_tag_by_meal_title" = "Tags by meal type";
|
||||
"stats_dishes_per_tag_title" = "Dishes per tag";
|
||||
"violations_banner_title" = "%d meal(s) break your rules";
|
||||
"violations_banner_cta" = "View";
|
||||
|
||||
@@ -460,3 +460,5 @@
|
||||
"violations_replace" = "Cambiar plato";
|
||||
"stats_tag_by_meal_title" = "Etiquetas por tipo de comida";
|
||||
"stats_dishes_per_tag_title" = "Platos por etiqueta";
|
||||
"violations_banner_title" = "%d comida(s) incumplen tus reglas";
|
||||
"violations_banner_cta" = "Ver";
|
||||
|
||||
@@ -460,3 +460,5 @@
|
||||
"violations_replace" = "Changer de plat";
|
||||
"stats_tag_by_meal_title" = "Étiquettes par type de repas";
|
||||
"stats_dishes_per_tag_title" = "Plats par étiquette";
|
||||
"violations_banner_title" = "%d repas ne respecte(nt) pas vos règles";
|
||||
"violations_banner_cta" = "Voir";
|
||||
|
||||
@@ -460,3 +460,5 @@
|
||||
"violations_replace" = "Cambia piatto";
|
||||
"stats_tag_by_meal_title" = "Etichette per tipo di pasto";
|
||||
"stats_dishes_per_tag_title" = "Piatti per etichetta";
|
||||
"violations_banner_title" = "%d pasto/i non rispettano le tue regole";
|
||||
"violations_banner_cta" = "Vedi";
|
||||
|
||||
@@ -460,3 +460,5 @@
|
||||
"violations_replace" = "Trocar prato";
|
||||
"stats_tag_by_meal_title" = "Etiquetas por tipo de refeição";
|
||||
"stats_dishes_per_tag_title" = "Pratos por etiqueta";
|
||||
"violations_banner_title" = "%d refeição(ões) quebram suas regras";
|
||||
"violations_banner_cta" = "Ver";
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -111,3 +111,4 @@ final class NextWeekNavigationUITests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.1.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>86</string>
|
||||
<string>87</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.1.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>86</string>
|
||||
<string>87</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
|
||||
Reference in New Issue
Block a user