CouleurEtiquette.swift 42 lignes · 1625 octets
import Foundation

/// Teinte d'une étiquette de tâche — port de `COULEURS_ETIQUETTE` et
/// `empreinte_fnv1a` de `Server/src/modeles.rs`, décalqué du Kotlin
/// `planning/CouleurEtiquette.kt`.
///
/// Deux tâches portant la même étiquette prennent la même couleur, sur le web
/// comme sur le téléphone. Le FNV-1a a été écrit explicitement côté serveur
/// plutôt que d'utiliser un hachage de bibliothèque, précisément pour être
/// reproductible ici. Les teintes de référence sont figées des trois côtés
/// (`teintes_de_reference_partagees_avec_le_mobile` / `teintesDeReference`).
enum CouleurEtiquette {
    static let palette = [
        "#3772CF", // bleu
        "#3FB985", // vert
        "#E89642", // ambre
        "#E5484D", // rouge
        "#8B5CF6", // violet
        "#0EA5E9", // cyan
        "#EC4899", // rose
        "#6B7280", // ardoise
    ]

    /// `nil` si la tâche n'a pas d'étiquette.
    static func pour(_ etiquette: String?) -> String? {
        let e = etiquette?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
        if e.isEmpty { return nil }
        // Le hachage est **non signé** sur 32 bits, comme en Rust : passer par
        // `Int` (64 bits, débordement fatal en Swift) donnerait un autre index.
        let index = Int(empreinteFnv1a(e) % UInt32(palette.count))
        return palette[index]
    }

    private static func empreinteFnv1a(_ texte: String) -> UInt32 {
        var h: UInt32 = 0x811c_9dc5
        for octet in Array(texte.utf8) {
            h ^= UInt32(octet)
            h = h &* 0x0100_0193
        }
        return h
    }
}