110807d239
- Eating out: tap any empty slot → "Mark as eating out"; shows teal indicator, skipped by auto-assign, counts as complete, tap again to unmark - Rule violations panel: access via wand long-press context menu when conflicts exist; shows all isRuleOverridden slots with Fix (clear) or Ignore (acknowledge) actions - Firebase Crashlytics integrated: CrashlyticsService + dSYM upload build phase, isPremium property tracked per session - PremiumSyncService: extracted premium state machine, StoreKit Transaction.updates listener, isPremium no longer synced via iCloud to avoid stale state - StoreManager: analytics on purchase/restore, bundle ID fallback for product ID lookup - Search bar contrast bug fixed: TextField now has explicit foreground color for dark mode - WelcomeStepView: redesigned onboarding welcome screen with week preview - Version bump: 1.0.5 build 22 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
74 lines
2.3 KiB
Swift
74 lines
2.3 KiB
Swift
import SwiftUI
|
|
|
|
struct EmptySlotView: View {
|
|
let mealType: MealType
|
|
let isDropTarget: Bool
|
|
let isValidDrop: Bool?
|
|
|
|
init(mealType: MealType, isDropTarget: Bool = false, isValidDrop: Bool? = nil) {
|
|
self.mealType = mealType
|
|
self.isDropTarget = isDropTarget
|
|
self.isValidDrop = isValidDrop
|
|
}
|
|
|
|
var body: some View {
|
|
VStack(spacing: 6) {
|
|
Image(systemName: mealType.icon)
|
|
.font(.system(size: 20))
|
|
.foregroundColor(Color(hex: "#C4C4C4"))
|
|
|
|
Text(LocalizedStringKey(mealType.rawValue))
|
|
.font(.mealMoodCaption)
|
|
.foregroundColor(.mealMoodTextSecondary)
|
|
}
|
|
.frame(maxWidth: .infinity, minHeight: 80)
|
|
.background(
|
|
RoundedRectangle(cornerRadius: 12)
|
|
.fill(Color(hex: "#F9F9F9"))
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 12)
|
|
.strokeBorder(
|
|
style: StrokeStyle(lineWidth: 2, dash: [5])
|
|
)
|
|
.foregroundColor(borderColor)
|
|
)
|
|
)
|
|
.animation(.easeInOut(duration: 0.2), value: isDropTarget)
|
|
}
|
|
|
|
private var borderColor: Color {
|
|
guard isDropTarget, let valid = isValidDrop else {
|
|
return Color(hex: "#E0E0E0")
|
|
}
|
|
return valid ? .mealMoodSuccess : .mealMoodError
|
|
}
|
|
}
|
|
|
|
struct EatingOutSlotView: View {
|
|
let mealType: MealType
|
|
|
|
var body: some View {
|
|
VStack(spacing: 6) {
|
|
Image(systemName: "fork.knife.circle")
|
|
.font(.system(size: 20))
|
|
.foregroundColor(Color(hex: "#A0C4B8"))
|
|
|
|
Text("slot_eating_out")
|
|
.font(.mealMoodCaption)
|
|
.foregroundColor(Color(hex: "#6B9E90"))
|
|
}
|
|
.frame(maxWidth: .infinity, minHeight: 80)
|
|
.background(
|
|
RoundedRectangle(cornerRadius: 12)
|
|
.fill(Color(hex: "#EEF8F5"))
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 12)
|
|
.strokeBorder(
|
|
style: StrokeStyle(lineWidth: 2, dash: [5])
|
|
)
|
|
.foregroundColor(Color(hex: "#A0C4B8"))
|
|
)
|
|
)
|
|
}
|
|
}
|