Files
FamilyMealPlanner/MealMood/Services/FeedbackStore.swift
T
alexandrev-tibco 84b74f9ea4 Autocomplete feedback loop: implicit rejection + weekly rating
A) Implicit: HomeViewModel tracks auto-assigned slot IDs after each
   autocomplete run. When the user manually replaces one of those dishes,
   the rejected dish ID is recorded in FeedbackStore (UserDefaults).
   AutocompleteEngine applies a 25% penalty per rejection (floor 0.30).

B) Explicit: WeekPlan gains userRating (0/1/-1). Past weeks with dishes
   show a compact 👍/👎 row (Premium only). Liked weeks boost their
   dishes (+0.20 each, max +0.50); disliked weeks penalise them
   (-0.25 each, max -0.50). Signal is intentionally modest so the
   period cycle score remains dominant.

Also adds Stats + week-rating localization strings to all 6 languages
(were missing from the previous commit).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 18:09:15 +02:00

29 lines
994 B
Swift

import Foundation
struct FeedbackStore {
private static let rejectionKey = "com.mealmood.dishRejections"
static func rejectionCounts() -> [UUID: Int] {
guard let data = UserDefaults.standard.data(forKey: rejectionKey),
let raw = try? JSONDecoder().decode([String: Int].self, from: data)
else { return [:] }
return Dictionary(uniqueKeysWithValues: raw.compactMap { k, v in
UUID(uuidString: k).map { ($0, v) }
})
}
static func recordRejection(for dishId: UUID) {
var raw: [String: Int]
if let data = UserDefaults.standard.data(forKey: rejectionKey),
let decoded = try? JSONDecoder().decode([String: Int].self, from: data) {
raw = decoded
} else {
raw = [:]
}
raw[dishId.uuidString, default: 0] += 1
if let encoded = try? JSONEncoder().encode(raw) {
UserDefaults.standard.set(encoded, forKey: rejectionKey)
}
}
}