Ver Fonte

better navigation prepare

better navigation prepare
Milan Jurkulak há 3 anos atrás
pai
commit
cca84dfc4f

+ 85 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/DrawerSheet.kt

@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.ui.components.navigation
+
+import androidx.compose.animation.animateContentSize
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.focusGroup
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.width
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.FocusState
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import androidx.tv.material3.DrawerState
+import androidx.tv.material3.DrawerValue
+import androidx.tv.material3.ExperimentalTvMaterial3Api
+import org.mjdev.tvlib.annotations.TvPreview
+
+@Suppress("IllegalExperimentalApiUsage")
+@OptIn(ExperimentalTvMaterial3Api::class, ExperimentalFoundationApi::class)
+@TvPreview
+@Composable
+fun DrawerSheet(
+    modifier: Modifier = Modifier,
+    drawerState: DrawerState = remember { DrawerState() },
+    sizeAnimationFinishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null,
+    content: @Composable (DrawerValue) -> Unit = {
+        Box(
+            modifier = Modifier
+                .width(200.dp)
+                .background(Color.LightGray, RectangleShape)
+        )
+    }
+) {
+    val initializationComplete = remember { mutableStateOf(false) }
+    val focusState = remember { mutableStateOf<FocusState?>(null) }
+    val focusRequester = remember { FocusRequester() }
+    LaunchedEffect(
+        drawerState.currentValue
+    ) {
+        if (drawerState.currentValue == DrawerValue.Open && focusState.value?.hasFocus == false) {
+            focusRequester.requestFocus()
+        }
+        initializationComplete.value = true
+    }
+    val internalModifier = Modifier
+        .focusRequester(focusRequester)
+        .animateContentSize(
+            finishedListener = sizeAnimationFinishedListener
+        )
+        .fillMaxHeight()
+        .then(modifier)
+        .onFocusChanged { state ->
+            focusState.value = state
+            if (initializationComplete.value) {
+                drawerState.setValue(
+                    if (state.hasFocus) DrawerValue.Open
+                    else DrawerValue.Closed
+                )
+            }
+        }
+        .focusGroup()
+    Box(
+        modifier = internalModifier
+    ) {
+        content.invoke(drawerState.currentValue)
+    }
+}

+ 97 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/ModalNavigationDrawer.kt

@@ -0,0 +1,97 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.ui.components.navigation
+
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.zIndex
+import androidx.tv.material3.DrawerState
+import androidx.tv.material3.DrawerValue
+import androidx.tv.material3.ExperimentalTvMaterial3Api
+import androidx.tv.material3.rememberDrawerState
+import org.mjdev.tvlib.annotations.TvPreview
+
+@ExperimentalTvMaterial3Api
+@TvPreview
+@Composable
+fun ModalNavigationDrawer(
+    modifier: Modifier = Modifier,
+    drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
+    scrimColor: Color = Color.Black.copy(alpha = 0.5f),
+    closeDrawerWidth: Dp = 80.dp,
+    drawerContent: @Composable (DrawerValue) -> Unit = {
+        Box(
+            modifier = Modifier
+                .background(Color.LightGray, RectangleShape)
+        )
+    },
+    content: @Composable () -> Unit = {
+        Box(modifier = Modifier.fillMaxSize())
+    }
+) {
+    val localDensity = LocalDensity.current
+    val closedDrawerWidth: MutableState<Dp?> = remember { mutableStateOf(null) }
+    val internalDrawerModifier =
+        Modifier
+            .zIndex(Float.MAX_VALUE)
+            .onSizeChanged {
+                if (closedDrawerWidth.value == null &&
+                    drawerState.currentValue == DrawerValue.Closed
+                ) {
+                    with(localDensity) {
+                        closedDrawerWidth.value = it.width.toDp()
+                    }
+                }
+            }
+
+    Box(modifier = modifier) {
+        DrawerSheet(
+            modifier = internalDrawerModifier.align(Alignment.CenterStart),
+            drawerState = drawerState,
+            sizeAnimationFinishedListener = { _, targetSize ->
+                if (drawerState.currentValue == DrawerValue.Closed) {
+                    with(localDensity) {
+                        closedDrawerWidth.value = targetSize.width.toDp()
+                    }
+                }
+            },
+            content = drawerContent
+        )
+        Box(
+            modifier = Modifier.padding(
+                closedDrawerWidth.value ?: closeDrawerWidth,
+                0.dp,
+                0.dp,
+                0.dp
+            )
+        ) {
+            content()
+            if (drawerState.currentValue == DrawerValue.Open) {
+                Canvas(Modifier.fillMaxSize()) {
+                    drawRect(scrimColor)
+                }
+            }
+        }
+    }
+}

+ 0 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/NavDrawerContent.kt

@@ -144,5 +144,4 @@ fun NavDrawerContent(
             }
             }
         }
         }
     }
     }
-
 }
 }

+ 35 - 31
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/Navigation.kt

@@ -23,8 +23,6 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.DrawerValue
 import androidx.tv.material3.DrawerValue
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.ExperimentalTvMaterial3Api
-import androidx.tv.material3.ModalNavigationDrawer
-import androidx.tv.material3.NavigationDrawer
 import org.mjdev.tvlib.annotations.TvPreview
 import org.mjdev.tvlib.annotations.TvPreview
 import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
 import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
 import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
 import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
@@ -67,36 +65,42 @@ fun Navigation(
             content()
             content()
         }
         }
     }
     }
-    if (navController.isMenuEnabled) {
-        val drawerContent: @Composable (DrawerValue) -> Unit = { state ->
-            NavDrawerContent(
-                backgroundColor = backgroundColor,
-                navController = navController,
-            )
-            navController.menuDrawerState.setValue(state)
-        }
-        if (modal) {
-            ModalNavigationDrawer(
-                modifier = modifier
-                    .fillMaxHeight()
-                    .background(backgroundColor, shape)
-                    .border(borderSize, borderColor, shape),
-                drawerState = navController.menuDrawerState,
-                content = mainContent,
-                drawerContent = drawerContent,
-            )
+    Box(
+        modifier
+            .fillMaxSize()
+            .recomposeHighlighter()
+    ) {
+        if (navController.isMenuEnabled) {
+            val drawerContent: @Composable (DrawerValue) -> Unit = { state ->
+                NavDrawerContent(
+                    backgroundColor = backgroundColor,
+                    navController = navController,
+                )
+                navController.menuDrawerState.setValue(state)
+            }
+            if (modal) {
+                ModalNavigationDrawer(
+                    modifier = modifier
+                        .fillMaxHeight()
+                        .background(backgroundColor, shape)
+                        .border(borderSize, borderColor, shape),
+                    drawerState = navController.menuDrawerState,
+                    content = mainContent,
+                    drawerContent = drawerContent,
+                )
+            } else {
+                NavigationDrawer(
+                    modifier = modifier
+                        .fillMaxHeight()
+                        .background(backgroundColor, shape)
+                        .border(borderSize, borderColor, shape),
+                    drawerState = navController.menuDrawerState,
+                    content = mainContent,
+                    drawerContent = drawerContent
+                )
+            }
         } else {
         } else {
-            NavigationDrawer(
-                modifier = modifier
-                    .fillMaxHeight()
-                    .background(backgroundColor, shape)
-                    .border(borderSize, borderColor, shape),
-                drawerState = navController.menuDrawerState,
-                content = mainContent,
-                drawerContent = drawerContent
-            )
+            mainContent()
         }
         }
-    } else {
-        mainContent()
     }
     }
 }
 }

+ 56 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/NavigationDrawer.kt

@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.ui.components.navigation
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.width
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.unit.dp
+import androidx.tv.material3.DrawerState
+import androidx.tv.material3.DrawerValue
+import androidx.tv.material3.ExperimentalTvMaterial3Api
+import androidx.tv.material3.rememberDrawerState
+import org.mjdev.tvlib.annotations.TvPreview
+import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
+
+@ExperimentalTvMaterial3Api
+@TvPreview
+@Composable
+fun NavigationDrawer(
+    modifier: Modifier = Modifier,
+    drawerState: DrawerState = rememberDrawerState(
+        if (isEditMode()) DrawerValue.Open else DrawerValue.Closed
+    ),
+    drawerContent: @Composable (DrawerValue) -> Unit = {
+        Box(
+            modifier = Modifier
+                .width(200.dp)
+                .background(Color.LightGray, RectangleShape)
+        )
+    },
+    content: @Composable () -> Unit = {
+        Box(modifier = Modifier.fillMaxSize())
+    }
+) {
+    Row(
+        modifier = modifier
+    ) {
+        DrawerSheet(
+            drawerState = drawerState,
+            content = drawerContent
+        )
+        content()
+    }
+}

+ 0 - 85
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/navigation/SettingsDrawer.kt

@@ -1,85 +0,0 @@
-/*
- * Copyright (c) Milan Jurkulák 2023.
- *  Contact:
- *  e: mimoccc@gmail.com
- *  e: mj@mjdev.org
- *  w: https://mjdev.org
- */
-
-package org.mjdev.tvlib.ui.components.navigation
-
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import androidx.tv.material3.DrawerState
-import androidx.tv.material3.DrawerValue
-import androidx.tv.material3.ExperimentalTvMaterial3Api
-import androidx.tv.material3.rememberDrawerState
-import org.mjdev.tvlib.annotations.TvPreview
-import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
-
-@OptIn(ExperimentalTvMaterial3Api::class)
-@TvPreview
-@Composable
-fun SettingsDrawer(
-    modifier: Modifier = Modifier,
-    drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
-    scrimColor: Color = Color.DarkGray.copy(alpha = 0.5f),
-    drawerWidth: Dp = 200.dp,
-    isEdit: Boolean = isEditMode(),
-    content: @Composable () -> Unit = {}
-) {
-//    val focusRequester = rememberFocusRequester()
-//    if (isEdit) drawerState.setValue(DrawerValue.Open)
-    content()
-//    Box(
-//        modifier = Modifier
-//            .conditional(drawerState.currentValue == DrawerValue.Open) {
-//                navigationBarsPadding()
-//                    .statusBarsPadding()
-//                    .fillMaxSize()
-//            }
-//            .conditional(drawerState.currentValue == DrawerValue.Closed) {
-//                width(0.dp)
-//            }
-//            .focusable()
-//            .onFocusChanged { state ->
-//                if (state.isFocused || state.hasFocus) {
-//                    focusRequester.freeFocus()
-//                }
-//            }
-//            .requestFocusOnTouch(focusRequester)
-//    ) {
-//        Column(
-//            modifier = Modifier
-//                .fillMaxSize()
-//                .background(
-//                    Brush.linearGradient(
-//                        colors = listOf(Color.Transparent, scrimColor),
-//                    ), RectangleShape
-//                ),
-//            horizontalAlignment = Alignment.End,
-//            verticalArrangement = Arrangement.Center
-//        ) {
-//            Column(
-//                modifier = modifier
-//                    .width(
-//                        when (drawerState.currentValue) {
-//                            DrawerValue.Open -> drawerWidth
-//                            else -> 0.dp
-//                        }
-//                    )
-//                    .fillMaxHeight(),
-//                horizontalAlignment = Alignment.Start,
-//                verticalArrangement = Arrangement.Top
-//            ) {
-//                TextAny(
-//                    text = "settings",
-//                    color = Color.White
-//                )
-//            }
-//        }
-//    }
-}