spb/lou-ka-ios Public
Lou·Ka iOS — app SwiftUI native de l'agrégateur de logements du Québec : filtres avancés, carte, stats, et mode Découverte (swipe) avec recommandation on-device
Swift 100%
1// -----------------------------------------------------------------------------2// Lou-Ka — Agrégateur de logements à louer (province de Québec)3// Auteur : Simon-Pierre Boucher — contact@spboucher.ai4// App.swift : point d'entrée, modèle global (facettes / sources / stats), onglets5// -----------------------------------------------------------------------------6import SwiftUI7import Observation89@MainActor10@Observable11final class AppModel {12 var facets: Facets?13 var sources: [SourceInfo] = []14 var stats: Stats?1516 private var loaded = false1718 func loadGlobals(force: Bool = false) async {19 if loaded && !force { return }20 loaded = true21 async let facetsTask = try? API.facets()22 async let sourcesTask = try? API.sources()23 async let statsTask = try? API.stats()24 let (f, s, st) = await (facetsTask, sourcesTask, statsTask)25 if let f { facets = f }26 if let s { sources = s.sources }27 if let st { stats = st }28 }2930 /// id de source → nom lisible (ex. « logisco » → « Logisco »)31 func sourceName(_ id: String) -> String {32 sources.first(where: { $0.id == id })?.name ?? id33 }34}3536@main37struct LouKaApp: App {38 @State private var model = AppModel()39 @State private var reco = RecoEngine()4041 init() {42 // Barre de navigation « éditoriale » : papier opaque, trait encre,43 // titres en Space Grotesk — cohérent sur toutes les pages.44 let nav = UINavigationBarAppearance()45 nav.configureWithOpaqueBackground()46 nav.backgroundColor = UIColor(LK.paper)47 nav.shadowColor = UIColor(LK.ink)48 var titleAttrs: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor(LK.ink)]49 var largeAttrs = titleAttrs50 if let f = UIFont(name: "SpaceGrotesk-Bold", size: 17) { titleAttrs[.font] = f }51 if let f = UIFont(name: "SpaceGrotesk-Bold", size: 30) { largeAttrs[.font] = f }52 nav.titleTextAttributes = titleAttrs53 nav.largeTitleTextAttributes = largeAttrs54 UINavigationBar.appearance().standardAppearance = nav55 UINavigationBar.appearance().scrollEdgeAppearance = nav56 }5758 var body: some Scene {59 WindowGroup {60 RootView()61 .environment(model)62 .environment(reco)63 .tint(LK.ink)64 // Le design Lou-Ka est un thème clair (papier/encre) : on le force65 // pour que les couleurs système (titres, champs, pickers) ne passent66 // jamais au blanc en mode sombre → texte invisible.67 .preferredColorScheme(.light)68 }69 }70}7172struct RootView: View {73 @Environment(AppModel.self) private var model7475 var body: some View {76 TabView {77 HomeView()78 .tabItem { Label("Annonces", systemImage: "list.bullet.rectangle.portrait") }79 DiscoverView()80 .tabItem { Label("Découvrir", systemImage: "rectangle.stack.badge.play") }81 MapTabView()82 .tabItem { Label("Carte", systemImage: "map") }83 StatsView()84 .tabItem { Label("Stats", systemImage: "chart.bar.xaxis") }85 SourcesView()86 .tabItem { Label("Sources", systemImage: "building.2") }87 }88 .task { await model.loadGlobals() }89 }90}91