Application iOS pour la gestion et l'analyse d'horaires de travail avec importation OCR automatique et widgets interactifs
Shifter est une application iOS native spécifiquement conçue pour les employés utilisant WorkJam qui souhaitent une segmentation détaillée de leurs heures de travail. ParticuliÚrement adaptée aux secteurs retail, restauration et services, elle permet d'importer automatiquement des captures d'écran de plannings WorkJam via OCR, d'analyser précisément la répartition horaire par type de shift (Shift 1, Shift 2, Shift 3, etc.), et de visualiser des statistiques détaillées (mensuel/trimestriel/annuel) via des widgets iOS natifs.
Les employés utilisant WorkJam pour leurs horaires reçoivent leurs plannings sous forme de captures d'écran, mais l'application ne propose aucune analyse détaillée par segment. Shifter élimine :
- â La saisie manuelle fastidieuse des horaires depuis WorkJam
- â L'impossibilitĂ© de se connecter directement Ă WorkJam pour rĂ©cupĂ©rer ses horaires
- â L'impossibilitĂ© d'analyser la rĂ©partition horaire par type de shift (Shift 1, Shift 2, Shift 3, etc.)
- â La difficultĂ© Ă comparer ses performances entre pĂ©riodes (mois/trimestre/annĂ©e)
- â L'absence de vision synthĂ©tique des heures par segment
- â Le risque de perte de donnĂ©es lors des rĂ©installations
â
Import OCR ultra-rapide depuis WorkJam : Capture d'Ă©cran â Reconnaissance texte â Shifts importĂ©s avec segments automatiquement
â
Connexion directe WorkJam : Synchronisation de vos horaires sans capture d'écran, directement depuis votre compte WorkJam
â
Segmentation détaillée par type de shift : Analyse précise de la répartition horaire (Shift 1, Shift 2, Shift 3, Pause, etc.)
â
Statistiques intelligentes : Analyse comparative par mois/trimestre/année avec % et delta par segment
â
Widgets iOS natifs : AccÚs instantané aux 3 segments prioritaires depuis l'écran d'accueil et écran verrouillé
â
Backup automatique : Restauration des données aprÚs réinstallation
â
Interface rétro-moderne : Inspirée de system.css (esthétique macOS classique)
â
Performance optimisée : 0 logs en production, regex pré-compilées, cache intelligent
| Composant | Technologie | RĂŽle |
|---|---|---|
| Framework UI | SwiftUI | Interface déclarative native iOS |
| Persistance | SwiftData | ORM moderne avec ModelContainer partagé |
| OCR | Vision Framework | Reconnaissance de texte dans les images |
| Widgets | WidgetKit | Widgets natifs iOS (Home + Lock Screen) |
| Partage de donnĂ©es | App Groups | Conteneur partagĂ© app â widget |
| Cache | UserDefaults + JSON | Backup automatique et restauration |
Shifter/
âââ WorkScheduleApp/ # Application principale iOS
â âââ WorkScheduleAppApp.swift # Point d'entrĂ©e avec ModelContainer
â âââ ContentView.swift # Vue principale (statistiques + filtres)
â âââ Models/
â â âââ WorkSchedule.swift # ModĂšle SwiftData (collection de shifts)
â â âââ Shift.swift # ModĂšle SwiftData (shift individuel)
â âââ ViewModels/
â â âââ ScheduleViewModel.swift # Logique mĂ©tier (OCR, backup, export)
â âââ Views/
â â âââ ManageDataView.swift # Gestion des shifts (liste/suppression)
â â âââ ShiftStatisticsView.swift # Statistiques dĂ©taillĂ©es par segment
â â âââ SystemCSSTheme.swift # ThĂšme visuel system.css
â â âââ AboutView.swift # Page Ă Propos (style macOS Classic)
â âââ Services/
â â âââ OCRService.swift # Service de reconnaissance de texte
â âââ Helpers/
â âââ FiscalCalendarHelper.swift # Logique trimestres fiscaux (Q1-Q4)
â âââ DateFormatterCache.swift # Cache pour formatage de dates
â
âââ ShifterWidget/ # Widget iOS (WidgetKit)
â âââ ShifterWidget.swift # Vues Home Screen + Lock Screen + TimelineProvider
â âââ WidgetDataProvider.swift # AccĂšs SwiftData depuis le widget
â âââ ShifterWidgetBundle.swift # Configuration du widget
â
âââ ShifterShareExtension/ # Extension de partage (import images)
âââ ShareViewController.swift # Controller pour partage d'images
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â IMPORT DE PLANNING â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
âŒ
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â 1. Capture d'Ă©cran (Photo Picker / Share Extension) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
âŒ
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â 2. OCRService.recognizeText(UIImage) â Vision Framework â
â - DĂ©tection de texte dans l'image â
â - Support multi-formats (WorkJam, PDF, etc.) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
âŒ
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â 3. OCRService.parseScheduleText(String) â Parsing Regex â
â - Extraction dates (format: "lundi 25 novembre") â
â - Extraction horaires (9h-17h, 10:00 AMâ11:30 AM, etc.) â
â - Extraction segments (Shift 1, Shift 2, etc.) â
â - Gestion indicateurs temporels ("hier", "Il y a X jours") â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
âŒ
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â 4. ScheduleViewModel.importScheduleFromImage() â
â - CrĂ©ation objets Shift avec SwiftData â
â - Sauvegarde dans ModelContainer (App Group) â
â - Backup JSON automatique (Documents/) â
â - Actualisation widget (WidgetCenter.reloadAllTimelines()) â
â - Synchronisation Apple Watch (WatchConnectivityManager) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
âŒ
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â DONNĂES PERSISTĂES â
â ââââââââââââââââââââââââââ ââââââââââââââââââââââââââ â
â â App Group Container â â Documents Backup â â
â â shifter.sqlite â â JSON (auto-restore) â â
â â (SwiftData partagĂ©) â â â â
â ââââââââââââââââââââââââââ ââââââââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â â
⌠âŒ
âââââââââââââââââââââ âââââââââââââââââââââââââ
â Application iOS â â Widget iOS â
â (Statistiques) â â (Top 3 Shifts) â
âââââââââââââââââââââ âââââââââââââââââââââââââ
Conteneur principal pour un ensemble d'horaires importés.
@Model
final class WorkSchedule: Identifiable {
var id: UUID
var title: String
var createdAt: Date
var imageData: Data? // Image originale (optionnel)
var rawOCRText: String? // Texte OCR brut (debug)
@Relationship(deleteRule: .cascade)
var shifts: [Shift] // Relation 1-N avec Shift
// Propriétés calculées
var totalHours: Double // Total d'heures décimales
var totalHoursFormatted: String // Format "42.5h"
var locations: [String] // Lieux uniques triés
var segments: [String] // Segments uniques triés
}ModÚle représentant un shift individuel avec optimisation d'index.
@Model
final class Shift: Identifiable {
#Index<Shift>([\.date], [\.segment], [\.date, \.segment]) // Index composites
var id: UUID
var date: Date // Jour du shift
var startTime: Date // Heure de début
var endTime: Date // Heure de fin
var location: String // Lieu de travail
var segment: String // Type de shift (Shift 1, Shift 2, Shift 3...)
var notes: String
var isConfirmed: Bool
@Relationship(deleteRule: .nullify, inverse: \WorkSchedule.shifts)
var schedule: WorkSchedule?
// Propriété calculée
var duration: TimeInterval // Durée en secondes
var durationFormatted: String // Format "7h30"
}Pourquoi des index ?
Les index composites [\.date], [\.segment], [\.date, \.segment] accĂ©lĂšrent les requĂȘtes frĂ©quentes :
- Filtrage par période (mois/trimestre/année)
- Filtrage par segment
- Combinaisons pour statistiques
Service de reconnaissance de texte avec 636 lignes de logique complexe.
| Format Détecté | Exemple | Regex Utilisée |
|---|---|---|
| WorkJam dates | "lundi 25 novembre" |
workJamDateRegex |
| Temps relatif | "Il y a 3 jours", "hier" |
relativeTimeRegex |
| Horaires AM/PM | "10:00 AMâ11:30 AM" |
timeRangeAMPMRegex |
| Horaires 24h | "9h-17h", "9:00-17:00" |
timeRange24HRegex1/2 |
- Regex pré-compilées (
static let) : Ăvite la recompilation Ă chaque parsing - Cache de parsing : Stocke jusqu'Ă 20 rĂ©sultats rĂ©cents
- Queue concurrente : Thread-safe avec
DispatchQueue.concurrent - Logs conditionnels :
#if DEBUGpour 0 logs en production - 20 segments OCR : Setup, Cycle Counts, GB On Point, Connection, Roundtable, Onboarding, Visuals, etc.
// Texte OCR brut :
"""
lundi 25 novembre
9h-17h Shift 1 Lieu de travail A
17h-18h Pause
"""
// Résultat parsé :
[
(date: 2024-11-25, start: 09:00, end: 17:00, location: "Lieu de travail A", segment: "Shift 1"),
(date: 2024-11-25, start: 17:00, end: 18:00, location: "Lieu de travail A", segment: "Pause")
]ViewModel central gérant la logique métier (535 lignes).
Import OCR
func importScheduleFromImage(_ image: UIImage) async {
// 1. OCR
let text = try await ocrService.recognizeText(from: image)
// 2. Parsing
let parsedShifts = ocrService.parseScheduleText(text)
// 3. Sauvegarde SwiftData
let schedule = WorkSchedule(title: "Import \(Date())")
for parsed in parsedShifts {
let shift = Shift(date: parsed.date, startTime: parsed.startTime, ...)
schedule.shifts.append(shift)
}
modelContext.insert(schedule)
// 4. Backup automatique
await createAutoBackup()
// 5. Actualisation widget
WidgetCenter.shared.reloadAllTimelines()
// 6. Synchronisation Apple Watch
syncToWatch()
}Backup/Restauration Automatique
- Backup : Fichier JSON dans
Documents/shifter_auto_backup.json - Avantage : Survit aux réinstallations via Xcode (certificat développeur)
- Déclencheurs : AprÚs chaque import/modification de données
- Restauration : Automatique au lancement si SwiftData vide
Gestion des trimestres fiscaux personnalisés.
| Trimestre | Mois | Particularité |
|---|---|---|
| Q1 | Oct-Déc | Dernier trimestre année civile |
| Q2 | Jan-Mar | Premier trimestre année civile |
| Q3 | Avr-Juin | - |
| Q4 | Juil-Sept | - |
Pourquoi ces trimestres ?
Alignement avec l'année fiscale de l'entreprise (différent de l'année civile).
enum FiscalCalendarHelper {
static func fiscalQuarter(for date: Date) -> Int {
let month = Calendar.current.component(.month, from: date)
switch month {
case 1...3: return 2
case 4...6: return 3
case 7...9: return 4
default: return 1 // 10-12
}
}
static func quarterLabel(for date: Date) -> String {
"Q\(fiscalQuarter(for: date)) \(fiscalYear(for: date))"
}
}ShifterWidget.swift
âââ Provider (TimelineProvider)
â âââ placeholder() â Vue placeholder
â âââ getSnapshot() â Aperçu instantanĂ©
â âââ getTimeline() â EntrĂ©es timeline (rafraĂźchissement horaire)
â
âââ ShifterWidgetEntryView
â âââ Home Screen Widgets
â â âââ SmallWidgetView â Segment #1 avec %
â â âââ MediumWidgetView â Top 3 segments (liste compacte)
â â âââ LargeWidgetView â Top 3 segments (cartes dĂ©taillĂ©es)
â â
â âââ Lock Screen Widgets
â âââ CircularView â % segment principal
â âââ RectangularView â Nom shift + %
â âââ InlineView â Label trimestre
â
âââ WidgetDataProvider
âââ getTop3ShiftsWithStats() â [(segment, heures, %, delta)]
âââ getQuarterStats() â QuarterStats (heures totales, %)
Configuration App Group : group.com.davidguia.shifter
// WorkScheduleAppApp.swift (Application principale)
let appGroupURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "group.com.davidguia.shifter"
)!
let storeURL = appGroupURL.appendingPathComponent("shifter.sqlite")
let modelConfiguration = ModelConfiguration(url: storeURL)
let container = try ModelContainer(for: schema, configurations: [modelConfiguration])
// WidgetDataProvider.swift (Widget)
let containerURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "group.com.davidguia.shifter"
)!
let storeURL = containerURL.appendingPathComponent("shifter.sqlite")
modelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration])Résultat : Base de données SwiftData partagée entre app et widget.
Small Widget (Compact)
âââââââââââââââââââââââââ
â Q2 2025 46h / 160h â
â â
â Shift 1 â
â 46% â â Pourcentage (prioritĂ© espace limitĂ©)
â â
â +2h vs Q1 â
âââââââââââââââââââââââââ
Medium Widget (Liste Top 3)
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Q2 2025 46h / 160h â
â â
â 1. Shift 1 7h30 46% +2h vs Q1 â
â 2. Shift 2 5h00 31% -1h vs Q1 â
â 3. Shift 3 3h45 23% +0.5h vs Q1 â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
Large Widget (Cartes Détaillées)
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Q2 2025 46h / 160h â
â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â 1. Shift 1 â â
â â 7h30 âą 46% â â
â â +2h vs Q1 â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â 2. Shift 2 â â
â â 5h00 âą 31% â â
â â -1h vs Q1 â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â 3. Shift 3 â â
â â 3h45 âą 23% â â
â â +0.5h vs Q1 â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
Déclencheurs de rafraßchissement :
- Import de nouveaux shifts â
WidgetCenter.shared.reloadAllTimelines() - Suppression de shift â
WidgetCenter.shared.reloadAllTimelines()+syncToWatch() - Suppression complĂšte â
WidgetCenter.shared.reloadAllTimelines()+syncToWatch() - Timeline automatique â Toutes les heures
Filtrage Widget :
- Exclut segment
"Général"(comme l'app principale) - Garde uniquement les shifts du trimestre fiscal en cours
- Calcule delta vs trimestre précédent
Inspiration : Esthétique macOS classique (System 7, Mac OS 9)
Palette de Couleurs
extension Color {
static let systemBeige = Color(red: 0.95, green: 0.94, blue: 0.90) // Fond principal
static let systemBorder = Color(red: 0.30, green: 0.30, blue: 0.30) // Bordures
static let systemText = Color.black // Texte principal
}Typographie
- Titres :
.system(.title, design: .monospaced)â Police monospacĂ©e rĂ©tro - Corps :
.system(.body, design: .monospaced) - Statistiques :
.system(size: 26, weight: .bold, design: .monospaced)
Composants Visuels
- Bordures 2px noires
- Coins arrondis 8px
- Ombres légÚres pour profondeur
- Espacements généreux (12-16pt)
| Période | Description | Cas d'Usage |
|---|---|---|
| Mois | Vue mensuelle avec jours travaillés | Suivi quotidien, horaires hebdomadaires |
| Trimestre | Vue trimestrielle fiscale (Q1-Q4) | Objectifs trimestriels, comparaison |
| Année | Vue annuelle complÚte | Bilan annuel, tendances long terme |
Par Période
- Total d'heures travaillées
- Nombre de shifts
- Jours travaillés
- Heures moyennes/jour
Par Segment
- Heures totales par type de shift
- Pourcentage du total
- Delta vs pĂ©riode prĂ©cĂ©dente (ââ)
- Ranking (Top 3 pour widget)
Exemple de Calcul Delta
// Trimestre actuel (Q2 2025)
Shift 1: 7h30
// Trimestre précédent (Q1 2025)
Shift 1: 5h30
// Delta
+2h vs Q1 (7h30 - 5h30 = +2h)Certificats de dĂ©veloppement Xcode expirent aprĂšs 7 jours â App devient inutilisable.
SystĂšme d'Alertes Progressives
| Jours Restants | Badge | Alerte | Action |
|---|---|---|---|
| 6-7 jours | đą Vert | Aucune | - |
| 4-5 jours | đą Vert | Aucune | - |
| 2-3 jours | đ Orange | Avertissement | Notification douce |
| 0-1 jour | đŽ Rouge | URGENT | Modal bloquante |
Badge Visuel dans l'App
private var daysRemaining: Int {
if UserDefaults.standard.object(forKey: "firstInstallDate") == nil {
UserDefaults.standard.set(Date(), forKey: "firstInstallDate")
}
let installDate = UserDefaults.standard.object(forKey: "firstInstallDate") as! Date
let expiryDate = Calendar.current.date(byAdding: .day, value: 7, to: installDate)!
let components = Calendar.current.dateComponents([.day], from: Date(), to: expiryDate)
return max(0, components.day ?? 0)
}Backup Automatique comme Filet de Sécurité
- Fichier JSON dans
Documents/survit à la réinstallation - Restauration automatique au prochain lancement
- Limitation : Fonctionne uniquement avec mĂȘme certificat dĂ©veloppeur
đ Guide d'Installation Complet (INSTALLATION.md) - Instructions dĂ©taillĂ©es pour certificat gratuit
- macOS : Sonoma 15.0+ (pour Xcode)
- Xcode : 26.0+ (pour Swift 6 / iOS 26)
- iOS : 26.0+ (appareil physique ou simulateur)
- Compte Développeur Apple : Gratuit (certificat 7 jours) ou payant ($99/an)
-
Ouvrir le projet
cd Shifter open WorkScheduleApp.xcodeproj -
Configurer Signing & Capabilities
- Sélectionner la target
WorkScheduleApp - Onglet "Signing & Capabilities"
- Choisir votre équipe de développement
- Activer "Automatically manage signing"
â ïž Important : RĂ©pĂ©ter pour les targetsShifterWidgetetShifterShareExtension - SĂ©lectionner la target
-
Configurer App Groups
- Vérifier que l'App Group
group.com.davidguia.shifterest actif pour :- â WorkScheduleApp
- â ShifterWidget
- â ShifterShareExtension
Si vous changez l'identifiant, modifier dans :
WorkScheduleAppApp.swiftWidgetDataProvider.swiftShareViewController.swift
- Vérifier que l'App Group
-
Build & Run
Product â Run (âR)
- Connecter iPhone via USB
- Sélectionner appareil dans Xcode (en haut à gauche)
- Build & Run (âR)
- Sur iPhone : ParamĂštres â GĂ©nĂ©ral â Gestion des appareils â Faire confiance au dĂ©veloppeur
- Lancer l'app â Ăcran vide "Aucun shift trouvĂ©"
- Appuyer sur â (en haut Ă droite)
- Choisir "Importer Capture d'écran"
- Sélectionner une capture de planning WorkJam
- Attendre l'OCR (1-3 secondes)
- Valider les shifts détectés
Format Attendu :
lundi 25 novembre
9h-17h Shift 1 Lieu de travail A
17h-18h Pause
mardi 26 novembre
10:00 AMâ6:00 PM Shift 2 Lieu de travail A
- Segmented Control en haut : Mois / Trimestre / Année
- FlĂšches âïž â¶ïž : Naviguer entre pĂ©riodes
- Statistiques : Mise Ă jour automatique
- Liste scrollable : Tous les segments avec heures/% /delta
- Exclut "Général" : Segments utiles uniquement
- Tri par heures : Du plus grand au plus petit
Menu ⯠(en haut à gauche)
- Gérer les données : Liste complÚte des shifts
- Supprimer un shift (swipe gauche)
- Supprimer tout (bouton rouge en bas)
- Exporter JSON : Sauvegarde manuelle
- Importer JSON : Restauration manuelle
- Ă propos : Informations app + certificat
Ajout Widget
- Ăcran d'accueil iPhone â Appui long
- Toucher â (en haut Ă gauche)
- Chercher "Shifter"
- Choisir taille : Small / Medium / Large
- Ajouter au Widget
RafraĂźchissement
- Automatique : Toutes les heures
- Manuel : Modifier des shifts dans l'app â Widget mis Ă jour instantanĂ©ment
Conventions de Nommage
- Fichiers : PascalCase (
ScheduleViewModel.swift) - Classes/Structs : PascalCase (
WorkSchedule,OCRService) - Propriétés/Méthodes : camelCase (
totalHours,importSchedule()) - Constantes : camelCase (
appGroupIdentifier)
Architecture MVVM
View (SwiftUI) â ViewModel (@Published) â Model (SwiftData)
â
Service (OCR, Network...)
Commentaires
// MARK: -: Sections majeures///: Documentation API (visible QuickHelp)//: Commentaires inline
- Index SwiftData : RequĂȘtes 3x plus rapides sur
dateetsegment - Cache OCR : Ăvite parsing redondant (20 entrĂ©es max)
- Regex statiques : Pré-compilation avec
static let(gain 40% CPU) - DateFormatterCache : Réutilisation formatters (évite allocations répétées)
- Logs production : 40
print()enveloppés dans#if DEBUG(0 logs en Release) - Compilation wholemodule : Optimisations cross-fichiers activées
- WatchConnectivity optimisé : Envoi différentiel uniquement si données changées
Test Manuel Recommandé
- Import de 10+ shifts variés
- Vérifier statistiques mensuel/trimestriel/annuel
- Tester widget Small/Medium/Large
- Simuler expiration certificat (modifier date install)
- Tester backup/restauration (supprimer app â rĂ©installer)
Cas Limites à Vérifier
- Import texte vide
- Import sans dates détectées
- Import avec formats horaires mixtes
- Trimestres Ă cheval sur annĂ©es (Q1 2024 â Q2 2025)
- Suppression complĂšte puis restauration
- Swift 6.0 : Conformité complÚte (Sendable, @unchecked Sendable, @preconcurrency)
- iOS 26.0 : Deployment target mis à jour, correction dépréciations
- Suppression Apple Watch : Codebase allégé, target WatchConnectivity retirée
- Migration @Observable : Remplacement @ObservableObject/Published (Swift 17+/26)
- Navigation intelligente : Boutons désactivés sur périodes sans données, saut automatique aux périodes renseignées
- Optimisation assets (-92%) : pngquant sur tous les PNG, 37.8 Mo â 2.8 Mo
- Suppression imagesets redondants : 3 doublons d'icÎnes 1024px supprimés
- Previews icÎnes optimisées : AppIconDarkPreview (16 Ko) + AppIconTintedPreview (14 Ko) à 210px
- Refonte page Ă Propos : Style fenĂȘtres macOS Classic, suppression lien GitHub
- IcÎnes alternatives : Dark / Tinted sélectionnables dans l'app
- Ajout des icĂŽnes d'application (multiple variants)
- SystÚme de mise en cache optimisé
- Navigation optimisée dans les vues d'horaires
- Saisie manuelle de shifts
- Import ZIP de données
- Logger d'application (AppLogger)
- Layout optimisĂ© avec en-tĂȘte/pied de page fixes
- Support Apple Watch complet (WatchConnectivity)
- Synchronisation automatique iPhone â Watch
- Widgets Lock Screen iOS 16+
- 7 nouveaux segments OCR détectés
- Optimisations performance (40 print() en DEBUG)
- Support TestFlight (distribution beta)
- Notifications push pour shifts Ă venir
- Export PDF des statistiques
- Synchronisation iCloud
- Graphiques de tendances
- Widget interactif (boutons)
- Publication App Store
- Intégration Calendrier iOS
- Machine Learning pour prédictions horaires
- Siri Shortcuts
MIT License
Copyright (c) 2025 David Guia
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
David Guia
- GitHub: @david-guia
- Email: [email protected]
- Apple : Frameworks SwiftUI, SwiftData, Vision, WidgetKit
- system.css : Inspiration design (sakofchit/system.css)
- WorkJam : Format de plannings source
- Building Widgets with SwiftUI
- OCR with Vision Framework
- SwiftData Best Practices
- WatchConnectivity Programming Guide
Fait avec â€ïž pour simplifier la vie des travailleurs Ă horaires variables


