Nucleus
OS integration

Détecteur de mode sombre

Détectez le mode sombre du système d'exploitation depuis Kotlin et recomposez votre interface Compose quand le thème change.

darkmode-detector indique si le système d'exploitation est en mode sombre et vous prévient lorsque cela change. Il fournit un composable isSystemInDarkMode() qui recompose aux changements de thème, ainsi qu'une API impérative IDarkModeDetector utilisable hors de Compose. macOS, Windows et Linux sont pris en charge.

Ajouter la dépendance

build.gradle.kts
dependencies {
    implementation("dev.nucleusframework:nucleus.darkmode-detector:2.0.7")
}

Détecter le mode sombre dans Compose

Appelez isSystemInDarkMode() et utilisez le résultat pour choisir votre palette de couleurs. Le composable recompose quand le thème système change :

import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import dev.nucleusframework.darkmodedetector.isSystemInDarkMode

@Composable
fun App() {
    val isDark = isSystemInDarkMode()
    MaterialTheme(
        colorScheme = if (isDark) darkColorScheme() else lightColorScheme(),
    ) {
        // Le contenu recompose quand le thème de l'OS bascule.
    }
}

Le isSystemInDarkTheme() natif de Compose lit le thème de l'OS une seule fois et ne se met pas à jour quand l'utilisateur change de thème à l'exécution. isSystemInDarkMode() renvoie la valeur courante et enregistre un listener qui déclenche une recomposition à chaque changement.

Dans un @Preview (quand LocalInspectionMode vaut true), isSystemInDarkMode() délègue au isSystemInDarkTheme() de Compose, pour que les previews s'affichent sans détecteur actif.

Fonctionnement

Chaque plateforme lit le thème système via un pont natif JNI et surveille les changements de l'OS. Aucun polling n'est utilisé : le détecteur réagit aux notifications de changement émises par l'OS lui-même.

  • macOS : lit la préférence système AppleInterfaceStyle et enregistre un observateur via NSDistributedNotificationCenter.
  • Windows : lit la valeur de registre HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\AppsUseLightTheme et la surveille avec RegNotifyChangeKeyValue sur un thread natif en arrière-plan.
  • Linux : lit la préférence color-scheme du portail XDG Desktop via l'interface D-Bus org.freedesktop.portal.Settings ; la valeur 1 signifie prefer-dark.

Sur les plateformes non prises en charge, getPlatformDarkModeDetector() renvoie NoopDarkModeDetector, qui rapporte toujours le mode clair et ignore les listeners.

Référence de l'API

Lire le thème courant

getPlatformDarkModeDetector() renvoie l'IDarkModeDetector de la plateforme courante. Appelez isDark() pour une lecture ponctuelle :

import dev.nucleusframework.darkmodedetector.getPlatformDarkModeDetector

val detector = getPlatformDarkModeDetector()
val dark: Boolean = detector.isDark()

Écouter les changements

Enregistrez un java.util.function.Consumer<Boolean> pour être notifié quand le thème change, et retirez-le quand vous n'en avez plus besoin :

import dev.nucleusframework.darkmodedetector.getPlatformDarkModeDetector
import java.util.function.Consumer

val detector = getPlatformDarkModeDetector()

val listener = Consumer<Boolean> { isDark ->
    println("mode sombre : $isDark")
}
detector.registerListener(listener)

// Plus tard, arrêtez de recevoir les mises à jour.
detector.removeListener(listener)

L'interface complète :

interface IDarkModeDetector {
    fun isDark(): Boolean
    fun registerListener(listener: Consumer<Boolean>)
    fun removeListener(listener: Consumer<Boolean>)
}

Utiliser un détecteur no-op

NoopDarkModeDetector implémente IDarkModeDetector sans toucher à l'OS. isDark() renvoie toujours false et les listeners sont ignorés — pratique pour les tests ou les environnements headless :

import dev.nucleusframework.darkmodedetector.IDarkModeDetector
import dev.nucleusframework.darkmodedetector.NoopDarkModeDetector

val detector: IDarkModeDetector = NoopDarkModeDetector

Et ensuite

  • Couleurs système — lisez la couleur d'accentuation du système et l'état contraste élevé.
  • Infos système — interrogez l'OS, le CPU, la mémoire et la batterie depuis Kotlin.
  • Intégration OS — le reste des API du système d'exploitation.