SPB Git

spb/vrai-prix-ios Public

App iOS native de Vrai-Prix — estimation immobilière transparente pour le Québec (SwiftUI, MapKit, Swift Charts)

Swift 100%
6.1 KB · 137 lines swift
Raw Blame History
1// Auteur : Simon-Pierre Boucher — contact@spboucher.ai2// À propos : la méthodologie en bref, les chiffres de validation, la conformité.3import SwiftUI45struct AboutView: View {6    var body: some View {7        NavigationStack {8            ScrollView {9                VStack(alignment: .leading, spacing: 18) {10                    VStack(alignment: .leading, spacing: 10) {11                        Wordmark(size: 34)12                        Text("La vraie valeur, sans boîte noire")13                            .font(.vpDisplay(19))14                            .foregroundStyle(Color.vpInk)15                            .textCase(.uppercase)16                        Text("Moteur d'évaluation immobilière transparent pour le Québec. Chaque calcul est montré en entier : comparables, ajustements en dollars, pondération, fourchette et confiance.")17                            .font(.vpBody(14.5))18                            .foregroundStyle(Color.vpInk2)19                    }20                    .padding(.top, 8)2122                    statsCard23                    methodCard24                    complianceCard2526                    VStack(alignment: .leading, spacing: 8) {27                        Link("www.vrai-prix.com", destination: URL(string: "https://www.vrai-prix.com")!)28                            .font(.vpDisplayMedium(15))29                            .foregroundStyle(Color.vpGreen)30                        Link("Méthodologie complète", destination: URL(string: "https://www.vrai-prix.com/methodologie")!)31                            .font(.vpBody(13.5))32                            .foregroundStyle(Color.vpInk2)33                        Link("Conditions d'utilisation", destination: URL(string: "https://www.vrai-prix.com/conditions")!)34                            .font(.vpBody(13.5))35                            .foregroundStyle(Color.vpInk2)36                        Link("Politique de confidentialité", destination: URL(string: "https://www.vrai-prix.com/confidentialite")!)37                            .font(.vpBody(13.5))38                            .foregroundStyle(Color.vpInk2)39                        Text("Simon-Pierre Boucher — contact@spboucher.ai")40                            .font(.vpMono(10))41                            .foregroundStyle(Color.vpInk3)42                            .padding(.top, 6)43                    }44                    .padding(.bottom, 16)45                }46                .padding(16)47            }48            .background(Color.vpPaper)49            .toolbar {50                ToolbarItem(placement: .principal) { Wordmark(size: 20) }51            }52            .navigationBarTitleDisplayMode(.inline)53            .toolbarBackground(Color.vpPaper, for: .navigationBar)54            .toolbarBackground(.visible, for: .navigationBar)55        }56    }5758    private var statsCard: some View {59        VStack(alignment: .leading, spacing: 12) {60            Kicker(text: "Les chiffres qui comptent")61            LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 14) {62                stat("3 747 008", "unités d'évaluation")63                stat("745 119", "ventes réelles")64                stat("11,0 %", "erreur médiane (MdAPE)")65                stat("0,995", "ratio médian (IAAO ✓)")66                stat("2,01 billions $", "valeur de la province")67                stat("99,88 %", "fusion spatiale réussie")68            }69        }70        .padding(18)71        .vpCard()72    }7374    private func stat(_ value: String, _ label: String) -> some View {75        VStack(alignment: .leading, spacing: 3) {76            Text(value)77                .font(.vpDisplay(19))78                .foregroundStyle(Color.vpInk)79                .minimumScaleFactor(0.7)80                .lineLimit(1)81            Text(label.uppercased())82                .font(.vpMono(8.5))83                .tracking(0.6)84                .foregroundStyle(Color.vpInk3)85        }86        .frame(maxWidth: .infinity, alignment: .leading)87    }8889    private var methodCard: some View {90        VStack(alignment: .leading, spacing: 12) {91            Kicker(text: "Le moteur en cinq étapes")92            step(1, "Comparables", "Ventes candidates dans un rayon adaptatif (2,2 → 28 km), filtrées par type et superficie.")93            step(2, "Ajustements en dollars", "Conditions de marché (indice mensuel $/m²), superficie (50 % du $/m² marginal), âge (0,5 %/an).")94            step(3, "Pondération gaussienne", "Distance (σ 1 500 m), récence (σ 24 mois), similarité de superficie (σ 25 %).")95            step(4, "Fusion", "65 % modèle hédonique LightGBM + 35 % médiane pondérée des comparables.")96            step(5, "Confiance", "Nombre de comparables, dispersion et largeur de fourchette → indice A/B/C/D.")97        }98        .padding(18)99        .vpCard()100    }101102    private func step(_ n: Int, _ title: String, _ text: String) -> some View {103        HStack(alignment: .top, spacing: 12) {104            Text("0\(n)")105                .font(.vpMonoBold(11))106                .foregroundStyle(Color.vpGreen)107                .padding(.top, 2)108            VStack(alignment: .leading, spacing: 3) {109                Text(title.uppercased())110                    .font(.vpDisplay(13.5))111                    .foregroundStyle(Color.vpInk)112                Text(text)113                    .font(.vpBody(13))114                    .foregroundStyle(Color.vpInk2)115            }116        }117    }118119    private var complianceCard: some View {120        VStack(alignment: .leading, spacing: 10) {121            Kicker(text: "Données et conformité")122            Text("Données sources : rôles d'évaluation foncière du Québec (MAMH, licence ouverte), 6 millésimes 2021-2026. Les renseignements des propriétaires sont caviardés à la source. Conformité Loi 25.")123                .font(.vpBody(13.5))124                .foregroundStyle(Color.vpInk2)125            Text("Estimations statistiques à titre indicatif — ne remplacent pas une évaluation par un évaluateur agréé (OEAQ).")126                .font(.vpMono(9.5))127                .foregroundStyle(Color.vpInk3)128        }129        .padding(18)130        .vpCard()131    }132}133134#Preview {135    AboutView()136}137