Swift 100%
1// Auteur : Simon-Pierre Boucher — contact@spboucher.ai2// MortgageCard.swift — l'estimateur hypothécaire des fiches Immo·Ka : mise de3// fonds ajustable, taux modifiable, paiement mensuel calculé LOCALEMENT et en4// toute transparence (formule affichée en pied). Aucune donnée n'est envoyée.5import SwiftUI67struct MortgageCard: View {8 let price: Double9 let accent: Color10 @State private var downFraction: Double = 0.2011 @State private var rate: Double = 4.512 @State private var years: Int = 2513 @Environment(\.colorScheme) private var scheme1415 private var payment: Double {16 MortgageMath.monthlyPayment(price: price, downFraction: downFraction,17 annualRate: rate, years: years)18 }19 private var down: Double { price * downFraction }2021 var body: some View {22 VStack(alignment: .leading, spacing: 12) {23 UniverseSectionHeader(title: "Paiement hypothécaire estimé", accent: accent)2425 HStack(alignment: .firstTextBaseline, spacing: 6) {26 Text(payment.money0)27 .font(KAFont.display(28))28 .foregroundStyle(accent)29 .contentTransition(.numericText())30 Text("/ mois")31 .font(KAFont.mono(10))32 .foregroundStyle(.secondary)33 }34 .animation(.snappy, value: payment)3536 VStack(alignment: .leading, spacing: 4) {37 HStack {38 Text("Mise de fonds")39 .font(.caption.weight(.semibold))40 Spacer()41 Text("\(Int(downFraction * 100)) % · \(down.money0)")42 .font(KAFont.mono(10))43 .foregroundStyle(accent)44 }45 Slider(value: $downFraction, in: 0.05...0.5, step: 0.05)46 .tint(accent)47 .accessibilityLabel("Mise de fonds")48 .accessibilityValue("\(Int(downFraction * 100)) pour cent")49 }5051 HStack(spacing: 12) {52 Stepper(value: $rate, in: 1...10, step: 0.25) {53 VStack(alignment: .leading, spacing: 1) {54 Text("TAUX").font(KAFont.mono(8)).foregroundStyle(.secondary)55 Text(String(format: "%.2f %%", rate))56 .font(.subheadline.weight(.bold))57 }58 }59 .accessibilityLabel("Taux d'intérêt annuel")60 Stepper(value: $years, in: 5...30, step: 5) {61 VStack(alignment: .leading, spacing: 1) {62 Text("AMORTISSEMENT").font(KAFont.mono(8)).foregroundStyle(.secondary)63 Text("\(years) ans").font(.subheadline.weight(.bold))64 }65 }66 .accessibilityLabel("Période d'amortissement")67 }6869 Text("Estimation indicative calculée sur votre appareil — taxes, assurance SCHL et frais exclus.")70 .font(.caption2).foregroundStyle(.tertiary)71 }72 .padding(14)73 .frame(maxWidth: .infinity, alignment: .leading)74 .kaCard(accent: accent)75 }76}77