2.0: dictado de platos/ingredientes + calendario más alto en iPad/Mac
- Dictado por voz (Speech/SFSpeechRecognizer, on-device) en el nombre de plato y en ingredientes, con transcripción en vivo. - Un solo texto dictado se separa en ingredientes individuales vía Apple Foundation Models on-device (IngredientParser), con fallback heurístico. - Permisos de micrófono y reconocimiento de voz en Info.plist. - Cadenas de dictado en los 6 idiomas. - iPad/Mac: el calendario reclama ~50% de la altura disponible en lugar de quedar fijo a ~240px; iPhone (compact) sin cambios. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
This commit is contained in:
@@ -10,6 +10,7 @@ final class DishViewModel: ObservableObject {
|
||||
@Published var ingredients: [String] = []
|
||||
@Published var photoData: Data?
|
||||
@Published var isGeneratingIngredients: Bool = false
|
||||
@Published var isParsingIngredients: Bool = false
|
||||
@Published var showTagSelector: Bool = false
|
||||
@Published var showDeleteAlert: Bool = false
|
||||
@Published var showAssignedDeleteAlert: Bool = false
|
||||
@@ -60,6 +61,25 @@ final class DishViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits a dictated phrase into individual ingredient lines and appends
|
||||
/// them to the current draft, dropping any empty placeholder rows first.
|
||||
/// No-op on empty input or while a parse is already running.
|
||||
func addDictatedIngredients(_ text: String, language: AppLanguage) {
|
||||
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !trimmed.isEmpty, !isParsingIngredients else { return }
|
||||
isParsingIngredients = true
|
||||
Task {
|
||||
let lines = await IngredientParser.parse(trimmed, language: language)
|
||||
await MainActor.run {
|
||||
self.isParsingIngredients = false
|
||||
guard !lines.isEmpty else { return }
|
||||
self.ingredients.removeAll { $0.trimmingCharacters(in: .whitespaces).isEmpty }
|
||||
self.ingredients.append(contentsOf: lines)
|
||||
AnalyticsService.logIngredientsGenerated(lineCount: lines.count, source: "dictation")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func save(context: ModelContext) {
|
||||
let trimmedName = name.trimmingCharacters(in: .whitespaces)
|
||||
guard !trimmedName.isEmpty else { return }
|
||||
|
||||
Reference in New Issue
Block a user