Add AI enablement guidance with reason-specific UI and localized translations

Show specific guidance when Apple Intelligence is unavailable:
- Device not eligible: "iPhone 15 Pro or later required"
- Not enabled: step-by-step path + "Open Settings" button
- Model downloading: "Please wait" + "Try Again" button
- Pre-iOS 26: "Update required"

Auto re-checks availability when app returns to foreground so enabling
Apple Intelligence in Settings immediately triggers insight generation.

Adds translations for all new AI strings across de, es, fr, ja, ko, pt-BR.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-04-04 21:36:04 -05:00
parent 7a6c4056d8
commit b0cd4be8d7
4 changed files with 19737 additions and 18882 deletions

View File

@@ -40,6 +40,7 @@ class InsightsViewModel: ObservableObject {
@Published var allTimeLoadingState: InsightLoadingState = .idle
@Published var isAIAvailable: Bool = false
@Published var aiUnavailableReason: AIUnavailableReason = .preiOS26
// MARK: - Dependencies
@@ -57,10 +58,12 @@ class InsightsViewModel: ObservableObject {
let service = FoundationModelsInsightService()
insightService = service
isAIAvailable = service.isAvailable
aiUnavailableReason = service.unavailableReason
service.prewarm()
} else {
insightService = nil
isAIAvailable = false
aiUnavailableReason = .preiOS26
}
dataListenerToken = DataController.shared.addNewDataListener { [weak self] in
@@ -185,14 +188,10 @@ class InsightsViewModel: ObservableObject {
return
}
// Check if AI is available
// Check if AI is available show reason-specific guidance
guard isAIAvailable else {
updateInsights([Insight(
icon: "brain.head.profile",
title: "AI Unavailable",
description: "Apple Intelligence is required for personalized insights. Please enable it in Settings.",
mood: nil
)])
let (icon, title, description) = unavailableMessage()
updateInsights([Insight(icon: icon, title: title, description: description, mood: nil)])
updateState(.error("AI not available"))
return
}
@@ -220,13 +219,47 @@ class InsightsViewModel: ObservableObject {
updateState(.error(error.localizedDescription))
}
} else {
updateInsights([Insight(
icon: "brain.head.profile",
title: "AI Unavailable",
description: "Apple Intelligence is required for personalized insights. Please enable it in Settings.",
mood: nil
)])
let (icon, title, description) = unavailableMessage()
updateInsights([Insight(icon: icon, title: title, description: description, mood: nil)])
updateState(.error("AI not available"))
}
}
// MARK: - Unavailable Messages
private func unavailableMessage() -> (icon: String, title: String, description: String) {
switch aiUnavailableReason {
case .deviceNotEligible:
return ("iphone.slash", "Device Not Supported",
String(localized: "AI insights require iPhone 15 Pro or later with Apple Intelligence."))
case .notEnabled:
return ("gearshape.fill", "Apple Intelligence Disabled",
String(localized: "Turn on Apple Intelligence in Settings → Apple Intelligence & Siri to unlock AI insights."))
case .modelDownloading:
return ("arrow.down.circle", "AI Model Downloading",
String(localized: "The AI model is still downloading. Please wait a few minutes and try again."))
case .preiOS26:
return ("arrow.up.circle", "Update Required",
String(localized: "AI insights require iOS 26 or later with Apple Intelligence."))
case .unknown:
return ("brain.head.profile", "AI Unavailable",
String(localized: "Apple Intelligence is required for personalized insights."))
}
}
/// Re-check AI availability (e.g., after returning from Settings)
func recheckAvailability() {
if #available(iOS 26, *), let service = insightService as? FoundationModelsInsightService {
service.checkAvailability()
let wasAvailable = isAIAvailable
isAIAvailable = service.isAvailable
aiUnavailableReason = service.unavailableReason
// If just became available, generate insights
if !wasAvailable && isAIAvailable {
service.prewarm()
generateInsights()
}
}
}
}