@@ -2,6 +2,7 @@ package com.tunjid.androidx.uidrivers
22
33import android.animation.ArgbEvaluator
44import android.animation.ValueAnimator
5+ import android.annotation.SuppressLint
56import android.graphics.Color
67import android.graphics.drawable.GradientDrawable
78import android.os.Build
@@ -14,6 +15,9 @@ import android.widget.EditText
1415import androidx.annotation.ColorInt
1516import androidx.annotation.DrawableRes
1617import androidx.core.graphics.ColorUtils
18+ import androidx.core.view.WindowCompat
19+ import androidx.core.view.WindowInsetsCompat
20+ import androidx.core.view.WindowInsetsControllerCompat
1721import androidx.core.view.doOnLayout
1822import androidx.core.view.isVisible
1923import androidx.core.view.updateLayoutParams
@@ -38,6 +42,7 @@ import com.tunjid.androidx.view.animator.ViewHider
3842import com.tunjid.androidx.view.util.PaddingProperty
3943import com.tunjid.androidx.view.util.innermostFocusedChild
4044import com.tunjid.androidx.view.util.spring
45+ import com.tunjid.androidx.view.util.viewDelegate
4146import com.tunjid.androidx.view.util.withOneShotEndListener
4247import kotlin.math.max
4348
@@ -92,9 +97,10 @@ class GlobalUiDriver(
9297 private val uiSizes = UISizes (host)
9398 private val fabExtensionAnimator = FabExtensionAnimator (binding.fab)
9499 private val toolbarHider = ViewHider .of(binding.toolbar).setDirection(ViewHider .TOP ).build()
100+ private val insetsController = WindowInsetsControllerCompat (host.window, binding.root)
95101 private val noOpInsetsListener = View .OnApplyWindowInsetsListener { _, insets -> insets }
96102 private val rootInsetsListener = View .OnApplyWindowInsetsListener { _, insets ->
97- liveUiState.value = uiState.reduceSystemInsets(insets, uiSizes.navBarHeightThreshold)
103+ liveUiState.value = uiState.reduceSystemInsets(WindowInsetsCompat .toWindowInsetsCompat( insets) , uiSizes.navBarHeightThreshold)
98104 // Consume insets so other views will not see them.
99105 insets.consumeSystemWindowInsets()
100106 }
@@ -144,6 +150,7 @@ class GlobalUiDriver(
144150
145151 UiState ::snackbarText.distinct onChanged this ::showSnackBar
146152 UiState ::navBarColor.distinct onChanged this ::setNavBarColor
153+ UiState ::statusBarColor.distinct onChanged host.window::setStatusBarColor
147154 UiState ::lightStatusBar.distinct onChanged this ::setLightStatusBar
148155 UiState ::fragmentContainerState.distinct onChanged this ::updateFragmentContainer
149156 UiState ::backgroundColor.distinct onChanged binding.contentRoot::animateBackground
@@ -221,39 +228,20 @@ class GlobalUiDriver(
221228 GradientDrawable .Orientation .BOTTOM_TOP ,
222229 intArrayOf(color, Color .TRANSPARENT ))
223230
224- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) uiFlagTweak {
225- if (color.isBrightColor) it or View .SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
226- else it and View .SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR .inv ()
227- }
231+ insetsController.isAppearanceLightNavigationBars = color.isBrightColor
228232 }
229233
230- private fun updateImmersivity (isImmersive : Boolean ) = uiFlagTweak { systemUiFlags ->
231- when (isImmersive) {
232- true -> (systemUiFlags
233- or View .SYSTEM_UI_FLAG_FULLSCREEN
234- or View .SYSTEM_UI_FLAG_HIDE_NAVIGATION
235- or View .SYSTEM_UI_FLAG_IMMERSIVE_STICKY
236- )
237- false -> (systemUiFlags
238- and View .SYSTEM_UI_FLAG_FULLSCREEN .inv ()
239- and View .SYSTEM_UI_FLAG_HIDE_NAVIGATION .inv ()
240- and View .SYSTEM_UI_FLAG_IMMERSIVE_STICKY .inv ()
241- )
242- }
234+ private fun updateImmersivity (isImmersive : Boolean ) {
235+ val systemBarsSetter = if (isImmersive) insetsController::hide else insetsController::show
236+ systemBarsSetter.invoke(WindowInsetsCompat .Type .statusBars() or WindowInsetsCompat .Type .navigationBars())
237+ insetsController.systemBarsBehavior = WindowInsetsControllerCompat .BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
243238 }
244239
245240 private fun setLightStatusBar (lightStatusBar : Boolean ) = when {
246- Build .VERSION .SDK_INT >= Build .VERSION_CODES .M -> uiFlagTweak { flags ->
247- if (lightStatusBar) flags or View .SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
248- else flags and View .SYSTEM_UI_FLAG_LIGHT_STATUS_BAR .inv ()
249- }
241+ Build .VERSION .SDK_INT >= Build .VERSION_CODES .M -> insetsController.isAppearanceLightStatusBars = lightStatusBar
250242 else -> host.window.statusBarColor = host.colorAt(if (lightStatusBar) R .color.transparent else R .color.black_50)
251243 }
252244
253- private fun uiFlagTweak (tweaker : (Int ) -> Int ) = host.window.decorView.run {
254- systemUiVisibility = tweaker(systemUiVisibility)
255- }
256-
257245 private fun setFabGlyphs (fabGlyphState : Pair <Int , CharSequence >) = host.runOnUiThread {
258246 val (@DrawableRes icon: Int , title: CharSequence ) = fabGlyphState
259247 fabExtensionAnimator.updateGlyphs(title, if (icon != 0 ) host.drawableAt(icon) else null )
@@ -285,14 +273,17 @@ class GlobalUiDriver(
285273 private val <T : Any ?> ((UiState ) -> T ).distinct get() = liveUiState.map(this ).distinctUntilChanged()
286274}
287275
276+ private var View .backgroundAnimator by viewDelegate<ValueAnimator ?>()
277+
278+ @SuppressLint(" Recycle" )
288279private fun View.animateBackground (@ColorInt to : Int ) {
289- val animator = getTag( R .id.doggo_image) as ? ValueAnimator
290- ? : ValueAnimator (). apply {
291- setTag( R .id.doggo_image, this )
292- setIntValues( Color . TRANSPARENT )
293- setEvaluator( ArgbEvaluator ())
294- addUpdateListener { setBackgroundColor(it.animatedValue as Int ) }
295- }
280+ val animator = backgroundAnimator ? : ValueAnimator (). apply {
281+ setTag( R .id.doggo_image, this )
282+ setIntValues( Color . TRANSPARENT )
283+ setEvaluator( ArgbEvaluator () )
284+ addUpdateListener { setBackgroundColor(it.animatedValue as Int ) }
285+ backgroundAnimator = this
286+ }
296287
297288 if (animator.isRunning) animator.cancel()
298289 animator.setIntValues(animator.animatedValue as Int , to)
@@ -324,12 +315,7 @@ private fun Window.assumeControl() {
324315 windowAttributes.layoutInDisplayCutoutMode = WindowManager .LayoutParams .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
325316 attributes = windowAttributes
326317 }
327- decorView.systemUiVisibility = FULL_CONTROL_SYSTEM_UI_FLAGS
318+ WindowCompat .setDecorFitsSystemWindows( this , false )
328319 navigationBarColor = context.colorAt(R .color.transparent)
329320 statusBarColor = context.colorAt(R .color.transparent)
330321}
331-
332- private const val FULL_CONTROL_SYSTEM_UI_FLAGS =
333- View .SYSTEM_UI_FLAG_LAYOUT_STABLE or
334- View .SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
335- View .SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
0 commit comments