a4dfb38feb
- Dish.isPriority: mark dishes as priority; auto-assign gives them 2.5x weight - Tag.dayRestriction: restrict tags to weekdays or weekend only - Auto-assign CTA banner shown when there are empty slots (was hidden in context menu) - Tap on filled slot opens picker to replace dish directly (no need to remove first) - Export callout visible as soon as ≥1 slot is filled (not only when week is complete) - WeekPlanShareView shows localized "TBD" / "Eating out" for empty/eating-out slots - Second Sunday 17:00 push notification to plan next week - DishDrawer sorts: priority first, then by historical usage, then alphabetically - Search in SlotDishPickerSheet already shipped in 1.0.5 (verified ✓) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
94 lines
3.2 KiB
Swift
94 lines
3.2 KiB
Swift
import Foundation
|
|
import SwiftData
|
|
|
|
@Model
|
|
final class Tag {
|
|
@Attribute(.unique) var id: UUID
|
|
var name: String
|
|
var nameEN: String
|
|
var color: String
|
|
var maxPerWeek: Int?
|
|
var noConsecutive: Bool
|
|
var noDuplicateInDay: Bool
|
|
var mealTypeRestriction: String? // "lunch", "dinner", nil
|
|
var dayRestriction: String? // nil = any day, "weekdays" = Mon-Fri, "weekend" = Sat-Sun
|
|
var isDefault: Bool
|
|
var sortOrder: Int
|
|
|
|
init(
|
|
id: UUID = UUID(),
|
|
name: String,
|
|
nameEN: String = "",
|
|
color: String,
|
|
maxPerWeek: Int? = nil,
|
|
noConsecutive: Bool = false,
|
|
noDuplicateInDay: Bool = false,
|
|
mealTypeRestriction: String? = nil,
|
|
dayRestriction: String? = nil,
|
|
isDefault: Bool = true,
|
|
sortOrder: Int = 0
|
|
) {
|
|
self.id = id
|
|
self.name = name
|
|
self.nameEN = nameEN
|
|
self.color = color
|
|
self.maxPerWeek = maxPerWeek
|
|
self.noConsecutive = noConsecutive
|
|
self.noDuplicateInDay = noDuplicateInDay
|
|
self.mealTypeRestriction = mealTypeRestriction
|
|
self.dayRestriction = dayRestriction
|
|
self.isDefault = isDefault
|
|
self.sortOrder = sortOrder
|
|
}
|
|
|
|
func localizedName(language: AppLanguage) -> String {
|
|
switch language.resolved() {
|
|
case .spanish: return name
|
|
case .english, .french, .german, .italian, .portugueseBrazil: return nameEN.isEmpty ? name : nameEN
|
|
case .system: return nameEN.isEmpty ? name : nameEN
|
|
}
|
|
}
|
|
|
|
var rulesDescription: String {
|
|
localizedRulesDescription(language: .spanish)
|
|
}
|
|
|
|
func localizedRulesDescription(language: AppLanguage) -> String {
|
|
let resolvedLanguage = language.resolved()
|
|
var parts: [String] = []
|
|
if let max = maxPerWeek {
|
|
switch resolvedLanguage {
|
|
case .spanish:
|
|
parts.append("Max \(max)/semana")
|
|
case .english, .french, .german, .italian, .portugueseBrazil:
|
|
parts.append("Max \(max)/week")
|
|
case .system:
|
|
parts.append("Max \(max)/week")
|
|
}
|
|
}
|
|
if noConsecutive {
|
|
parts.append(resolvedLanguage == .spanish ? "no consecutivo" : "no consecutive")
|
|
}
|
|
if noDuplicateInDay {
|
|
parts.append(resolvedLanguage == .spanish ? "no mismo día" : "no same day")
|
|
}
|
|
if let restriction = mealTypeRestriction {
|
|
if resolvedLanguage == .spanish {
|
|
parts.append(restriction == "lunch" ? "solo comida" : "solo cena")
|
|
} else {
|
|
parts.append(restriction == "lunch" ? "lunch only" : "dinner only")
|
|
}
|
|
}
|
|
if let day = dayRestriction {
|
|
switch (day, resolvedLanguage) {
|
|
case ("weekdays", .spanish): parts.append("entre semana")
|
|
case ("weekdays", _): parts.append("weekdays")
|
|
case ("weekend", .spanish): parts.append("fin de semana")
|
|
case ("weekend", _): parts.append("weekend")
|
|
default: break
|
|
}
|
|
}
|
|
return parts.isEmpty ? (resolvedLanguage == .spanish ? "Sin límite" : "No limit") : parts.joined(separator: ", ")
|
|
}
|
|
}
|