spb/poche Public
Agent personnel 100 % on-device — SwiftUI + Apple Foundation Models + EventKit + SwiftData. Aucune API, aucun serveur.
Swift 100%
1//2// AvailabilityView.swift3// Poche4//5// Author: Simon-Pierre Boucher6// Contact: contact@spboucher.ai7//89import SwiftUI10import FoundationModels1112/// Unavailability screens. Careful, apologetic, never guilt-tripping,13/// and never offering a replacement LLM (CLAUDE.md §2).14struct AvailabilityView: View {15 let reason: SystemLanguageModel.Availability.UnavailableReason16 let retry: () -> Void1718 var body: some View {19 ZStack {20 AppBackground()2122 VStack(spacing: Theme.spacingLarge) {23 Spacer()2425 ZStack {26 Circle()27 .fill(Theme.accentGradient.opacity(0.14))28 .frame(width: 108, height: 108)29 Image(systemName: symbolName)30 .font(.system(size: 44, weight: .light))31 .foregroundStyle(Theme.accentGradient)32 }3334 Text(title)35 .font(.title2.weight(.bold))36 .multilineTextAlignment(.center)37 .padding(.horizontal, Theme.spacingLarge)3839 Text(message)40 .font(.body)41 .foregroundStyle(.secondary)42 .multilineTextAlignment(.center)43 .padding(.horizontal, Theme.spacingLarge + 8)4445 actionButton4647 Spacer()4849 HStack(spacing: Theme.spacingSmall) {50 BrandMark(size: 20)51 Text("Poche — ton agent, sur ton appareil")52 .font(.footnote)53 .foregroundStyle(.secondary)54 }55 .padding(.bottom, Theme.spacingLarge)56 }57 }58 .fontDesign(.rounded)59 }6061 private var symbolName: String {62 switch reason {63 case .deviceNotEligible: "iphone.slash"64 case .appleIntelligenceNotEnabled: "gearshape"65 case .modelNotReady: "arrow.down.circle"66 @unknown default: "questionmark.circle"67 }68 }6970 private var title: String {71 switch reason {72 case .deviceNotEligible:73 "Cet iPhone ne peut pas faire tourner Poche"74 case .appleIntelligenceNotEnabled:75 "Apple Intelligence est désactivé"76 case .modelNotReady:77 "Le modèle se prépare"78 @unknown default:79 "L’intelligence sur l’appareil est indisponible"80 }81 }8283 private var message: String {84 switch reason {85 case .deviceNotEligible:86 "Poche fonctionne entièrement sur l’appareil, sans serveur. Cela demande la puce A17 Pro ou plus récente (iPhone 15 Pro et suivants). Sur cet iPhone, le modèle n’est pas disponible — et Poche ne le remplacera jamais par un service en ligne."87 case .appleIntelligenceNotEnabled:88 "Active Apple Intelligence dans Réglages pour que Poche puisse fonctionner, entièrement sur ton iPhone."89 case .modelNotReady:90 "Le modèle est en cours de téléchargement ou de préparation par le système. Cela peut prendre quelques minutes, notamment après une mise à jour ou en mode économie d’énergie."91 @unknown default:92 "Le modèle sur l’appareil n’est pas disponible pour le moment. Réessaie dans un instant."93 }94 }9596 @ViewBuilder97 private var actionButton: some View {98 switch reason {99 case .deviceNotEligible:100 EmptyView()101 case .appleIntelligenceNotEnabled:102 Button {103 if let url = URL(string: UIApplication.openSettingsURLString) {104 UIApplication.shared.open(url)105 }106 } label: {107 Text("Ouvrir Réglages")108 .font(.subheadline.weight(.semibold))109 .foregroundStyle(.white)110 .padding(.horizontal, Theme.spacingLarge)111 .padding(.vertical, Theme.spacingMedium - 2)112 .background(Theme.accentGradient)113 .clipShape(Capsule())114 }115 .buttonStyle(.plain)116 default:117 Button(action: retry) {118 Text("Réessayer")119 .font(.subheadline.weight(.semibold))120 .foregroundStyle(.white)121 .padding(.horizontal, Theme.spacingLarge)122 .padding(.vertical, Theme.spacingMedium - 2)123 .background(Theme.accentGradient)124 .clipShape(Capsule())125 }126 .buttonStyle(.plain)127 }128 }129}130