SPB Git

spb/focale Public

Swift 100%
4.3 KB · 123 lines swift
Raw Blame History
1//2//  OnboardingView.swift3//  Focale4//5//  Author: Simon-Pierre Boucher6//  Contact: contact@spboucher.ai7//8//  The #1 product risk (CLAUDE.md §12): full photo access refused.9//  We explain *why* before showing the system dialog — a naked dialog10//  is a refused permission is a lost install. The fact that nothing11//  leaves the device is the argument, said at exactly this spot.12//1314import SwiftUI1516struct OnboardingView: View {17    @Environment(AppModel.self) private var app18    @State private var isRequesting = false1920    var body: some View {21        VStack(spacing: 28) {22            Spacer()2324            Image(systemName: "camera.aperture")25                .font(.system(size: 64))26                .foregroundStyle(DesignTokens.accent)2728            Text("Tout ce que tu photographies\ndevient retrouvable")29                .font(.title2.bold())30                .multilineTextAlignment(.center)3132            VStack(alignment: .leading, spacing: 18) {33                explanationRow(34                    symbol: "iphone",35                    title: "Rien ne quitte ton iPhone. Jamais.",36                    detail: "L'analyse se fait entièrement sur l'appareil. Aucun serveur, aucun compte, aucune option cloud."37                )38                explanationRow(39                    symbol: "photo.stack",40                    title: "Tes photos restent exactement où elles sont",41                    detail: "Focale lit ta photothèque pour l'indexer. Aucune photo n'est copiée, déplacée ou modifiée."42                )43                explanationRow(44                    symbol: "magnifyingglass",45                    title: "L'accès complet, c'est ce qui rend la recherche possible",46                    detail: "Reçus, tableaux blancs, numéros de série : pour les retrouver, Focale doit pouvoir voir toute ta photothèque."47                )48            }49            .padding(.horizontal, 8)5051            Spacer()5253            Button {54                isRequesting = true55                Task {56                    await app.requestPhotoAccess()57                    isRequesting = false58                }59            } label: {60                Text("Autoriser l'accès à mes photos")61                    .font(.headline)62                    .frame(maxWidth: .infinity)63                    .padding(.vertical, 6)64            }65            .buttonStyle(.borderedProminent)66            .disabled(isRequesting)67        }68        .padding(24)69        .background(DesignTokens.surface)70    }7172    private func explanationRow(symbol: String, title: String, detail: String) -> some View {73        HStack(alignment: .top, spacing: 14) {74            Image(systemName: symbol)75                .font(.title3)76                .foregroundStyle(DesignTokens.accent)77                .frame(width: 30)78            VStack(alignment: .leading, spacing: 3) {79                Text(title).font(.subheadline.weight(.semibold))80                Text(detail)81                    .font(.footnote)82                    .foregroundStyle(DesignTokens.textSecondary)83            }84        }85    }86}8788/// Dedicated screen for `.limited` — an explanation, not an error message89/// (CLAUDE.md §2).90struct LimitedAccessView: View {91    var body: some View {92        VStack(spacing: 20) {93            Image(systemName: "photo.badge.exclamationmark")94                .font(.system(size: 52))95                .foregroundStyle(DesignTokens.accent)9697            Text("Focale a besoin de l'accès complet")98                .font(.title3.bold())99100            Text("""101            Avec un accès limité, Focale ne peut ni indexer ta photothèque \102            ni retrouver tes photos. Rien ne quitte ton iPhone — l'analyse \103            se fait entièrement sur l'appareil.104105            Dans Réglages → Confidentialité → Photos, choisis « Accès complet » \106            pour Focale.107            """)108            .font(.callout)109            .foregroundStyle(DesignTokens.textSecondary)110            .multilineTextAlignment(.center)111112            Button("Ouvrir les Réglages") {113                if let url = URL(string: UIApplication.openSettingsURLString) {114                    UIApplication.shared.open(url)115                }116            }117            .buttonStyle(.borderedProminent)118        }119        .padding(28)120        .background(DesignTokens.surface)121    }122}123