Skip to content

Instantly share code, notes, and snippets.

@sajjadyousefnia
Created June 2, 2025 16:44
Show Gist options
  • Save sajjadyousefnia/791dce73447f2fe60c9b2b98008b01d1 to your computer and use it in GitHub Desktop.
Save sajjadyousefnia/791dce73447f2fe60c9b2b98008b01d1 to your computer and use it in GitHub Desktop.
@Composable
fun SystemUIManager(
isDarkThemeForBottom: Boolean,
isDarkThemeForStatusBar: Boolean,
statusBarColor: Color,
navigationBarColor: Color,
hideStatusBar: Boolean = true,
hideNavigationBar: Boolean = true,
onSystemBarsVisibilityChange: (Boolean, Boolean) -> Unit
) {
var isProgrammaticChange = false // Flag to track programmatic changes
val view = LocalView.current
val window = (view.context as ComponentActivity).window
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
window.statusBarColor = statusBarColor.toArgb()
window.navigationBarColor = navigationBarColor.toArgb()
}
val windowInsetsController = WindowInsetsControllerCompat(window, view)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
window.statusBarColor = statusBarColor.toArgb()
window.navigationBarColor = navigationBarColor.toArgb()
view.setOnApplyWindowInsetsListener { _, insets ->
val isStatusBarVisible = insets.isVisible(WindowInsetsCompat.Type.statusBars())
val isNavigationBarVisible = insets.isVisible(WindowInsetsCompat.Type.navigationBars())
if (!isProgrammaticChange) {
onSystemBarsVisibilityChange(isStatusBarVisible, isNavigationBarVisible)
}
isProgrammaticChange = false // Reset the flag
insets
}
windowInsetsController.isAppearanceLightStatusBars = !isDarkThemeForStatusBar
windowInsetsController.isAppearanceLightNavigationBars = !isDarkThemeForBottom
if (hideStatusBar) {
isProgrammaticChange = true // Set the flag before programmatic change
windowInsetsController.hide(WindowInsetsCompat.Type.statusBars())
} else {
isProgrammaticChange = true // Set the flag before programmatic change
windowInsetsController.show(WindowInsetsCompat.Type.statusBars())
}
if (hideNavigationBar) {
isProgrammaticChange = true // Set the flag before programmatic change
windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars())
} else {
isProgrammaticChange = true // Set the flag before programmatic change
windowInsetsController.show(WindowInsetsCompat.Type.navigationBars())
}
} else {
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or if (hideStatusBar) View.SYSTEM_UI_FLAG_FULLSCREEN else 0
or if (hideNavigationBar) View.SYSTEM_UI_FLAG_HIDE_NAVIGATION else 0
or if (!isDarkThemeForStatusBar)
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
else 0
or if (!isDarkThemeForBottom)
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR else 0)
window.decorView.setOnSystemUiVisibilityChangeListener { visibility ->
val isStatusBarVisible = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0
val isNavigationBarVisible = visibility and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION == 0
if (!isProgrammaticChange) {
onSystemBarsVisibilityChange(isStatusBarVisible, isNavigationBarVisible)
}
isProgrammaticChange = false
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment