Ver código fonte

focusing fix, final

Milan Jurkulak 3 anos atrás
pai
commit
f3eec20605
18 arquivos alterados com 99 adições e 133 exclusões
  1. 9 0
      app/src/main/kotlin/org/mjdev/tvapp/base/extensions/ComposeExt.kt
  2. 21 28
      app/src/main/kotlin/org/mjdev/tvapp/base/extensions/ModifierExt.kt
  3. 1 11
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/badge/Badge.kt
  4. 3 4
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/button/Button.kt
  5. 18 5
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/Card.kt
  6. 2 4
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/CarouselCard.kt
  7. 0 7
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/ItemCard.kt
  8. 0 3
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/PhotoCard.kt
  9. 7 8
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/carousel/BigCarousel.kt
  10. 10 11
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/complex/FocusableBox.kt
  11. 5 19
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/complex/FocusableCard.kt
  12. 3 3
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/navigation/NavDrawerContent.kt
  13. 5 4
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/navigation/NavigationRow.kt
  14. 3 5
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/page/Page.kt
  15. 0 5
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/tv/Clock.kt
  16. 10 5
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/tv/Tabs.kt
  17. 2 6
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/tv/Title.kt
  18. 0 5
      app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/tv/UserPic.kt

+ 9 - 0
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/ComposeExt.kt

@@ -64,6 +64,15 @@ object ComposeExt {
     val MutableState<FocusState?>.isFocused
         get() = (value?.isFocused == true) || (value?.hasFocus == true)
 
+    val MutableState<FocusState?>.isNotFocused
+        get() = !isFocused
+
+    val FocusState?.isFocused
+        get() = (this?.isFocused == true) || (this?.hasFocus == true)
+
+    val FocusState?.isNotFocused
+        get() = !isFocused
+
 //    @Composable
 //    fun Any?.toDrawable(): Drawable {
 //        val context = LocalContext.current

+ 21 - 28
app/src/main/kotlin/org/mjdev/tvapp/base/extensions/ModifierExt.kt

@@ -8,19 +8,16 @@
 
 package org.mjdev.tvapp.base.extensions
 
-import android.annotation.SuppressLint
-import androidx.compose.foundation.clickable
-import androidx.compose.runtime.Composable
+import androidx.compose.foundation.gestures.detectTapGestures
 import androidx.compose.runtime.MutableState
 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 org.mjdev.tvapp.base.extensions.ComposeExt.isFocused
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusRequester
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
+import androidx.compose.ui.input.pointer.pointerInput
 
+@Suppress("MemberVisibilityCanBePrivate")
 object ModifierExt {
 
     fun Modifier.conditional(
@@ -33,28 +30,24 @@ object ModifierExt {
         }
     }
 
-    @SuppressLint("ComposableModifierFactory")
-    @Composable
-    // todo focus problem, requester not registered
-    fun Modifier.touchable(
-        focusState: MutableState<FocusState?> = rememberFocusState(),
-        focusRequester: FocusRequester = rememberFocusRequester(),
-        onFocus: FocusRequester.() -> Unit = {},
-        onClick: FocusRequester.() -> Unit = {},
-    ): Modifier = this then focusRequester(
-        focusRequester
-    ).onFocusChanged { state ->
-            focusState.value = state
-            if (focusState.isFocused) {
-                onFocus(focusRequester)
-            }
-        }
-        .clickable {
-            if (focusState.isFocused) {
-                onClick(focusRequester)
-            } else {
-                focusRequester.requestFocus()
-            }
+    fun Modifier.focusState(
+        focusState: MutableState<FocusState?>
+    ): Modifier = onFocusChanged { state ->
+        focusState.value = state
+    }
+
+    fun Modifier.onTouch(onTouch: () -> Unit) = pointerInput(this) {
+        detectTapGestures {
+            onTouch()
         }
+    }
+
+    fun Modifier.requestFocusOnTouch(
+        focusRequester: FocusRequester
+    ): Modifier = focusRequester(
+        focusRequester
+    ).onTouch {
+        focusRequester.requestFocus()
+    }
 
 }

+ 1 - 11
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/badge/Badge.kt

@@ -10,10 +10,8 @@ package org.mjdev.tvapp.base.ui.components.badge
 
 import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
-import androidx.compose.ui.focus.FocusState
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.tooling.preview.Preview
@@ -21,35 +19,27 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
-import androidx.tv.material3.ExperimentalTvMaterial3Api
-import androidx.tv.material3.MaterialTheme
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
 import org.mjdev.tvapp.base.ui.components.complex.FocusableBox
 import org.mjdev.tvapp.base.ui.components.text.CircleText
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Preview
 @Composable
 fun Badge(
     modifier: Modifier = Modifier,
     shape: Shape = CircleShape,
     count: Int = 0,
-    backGroundColor: Color = MaterialTheme.colorScheme.secondary,
+    backGroundColor: Color = Color.DarkGray,
     borderColor: Color = Color.White,
     borderSize: Dp = 2.dp,
     textColor: Color = Color.White,
     textSize: TextUnit = 20.sp,
     contentPadding: Dp = 2.dp,
-    focusState: MutableState<FocusState?> = rememberFocusState(),
-    onFocus: () -> Unit = {},
     onClick: () -> Unit = {}
 ) {
 
     FocusableBox(
         modifier = modifier.clip(CircleShape),
-        focusState = focusState,
         shape = shape,
-        onFocus = onFocus,
         onClick = onClick
     ) {
 

+ 3 - 4
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/button/Button.kt

@@ -33,7 +33,6 @@ import androidx.tv.material3.ButtonScale
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Glow
 import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
-import org.mjdev.tvapp.base.extensions.ModifierExt.touchable
 import org.mjdev.tvapp.base.ui.components.text.TextAny
 
 @Preview
@@ -64,9 +63,9 @@ fun Button(
 
     Button(
         modifier = modifier
-            .touchable(
-                focusState = focusState,
-            )
+//            .touchable(
+//                focusState = focusState,
+//            )
             .border(BorderStroke(borderSize, borderColor), shape),
         glow = glow,
         scale = scale,

+ 18 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/Card.kt

@@ -48,7 +48,12 @@ fun Card(
     shape: CardShape = CardDefaults.shape(),
     colors: CardColors = CardDefaults.colors(),
     border: CardBorder = CardDefaults.NO_BORDER,
-    glow: CardGlow = CardDefaults.NO_GLOW,
+    focusGlowColor: Color = Color.Green,
+    unFocusGlowColor: Color = Color.Transparent,
+    glow: CardGlow = CardDefaults.colorFocusGlow(
+        focusGlowColor,
+        unFocusGlowColor
+    ),
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     content: @Composable ColumnScope.() -> Unit = {}
 ) = androidx.tv.material3.Card(
@@ -75,6 +80,7 @@ val CardDefaults.NO_BORDER: CardBorder
         pressedBorder = Border.None
     )
 
+@Suppress("unused")
 @OptIn(ExperimentalTvMaterial3Api::class)
 val CardDefaults.NO_GLOW: CardGlow
     @Composable
@@ -87,15 +93,22 @@ val CardDefaults.NO_GLOW: CardGlow
 @OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 fun CardDefaults.colorFocusGlow(
-    color: Color = Color.Gray,
+    focusColor: Color = Color.Green,
+    onUnFocusColor: Color = Color.Transparent,
     elevation: Dp = 10.dp
 ): CardGlow = glow(
-    glow = Glow.None,
+    glow = Glow(
+        elevationColor = onUnFocusColor,
+        elevation = elevation
+    ),
     focusedGlow = Glow(
-        elevationColor = color,
+        elevationColor = focusColor,
         elevation = elevation
     ),
-    pressedGlow = Glow.None
+    pressedGlow = Glow(
+        elevationColor = onUnFocusColor,
+        elevation = elevation
+    )
 )
 
 @Suppress("UNUSED_PARAMETER")

+ 2 - 4
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/CarouselCard.kt

@@ -46,8 +46,7 @@ fun CarouselCard(
             placeholder = placeholder
         )
     },
-    onFocus: () -> Unit = {},
-    onClick: () -> Unit = {}
+    onClick: (item: Any?) -> Unit = {}
 ) {
     val isEdit = isEditMode()
     PhotoCard(
@@ -61,8 +60,7 @@ fun CarouselCard(
         focusState = focusState,
         placeholder = placeholder,
         imageRenderer = imageRenderer,
-        onFocus = { onFocus() },
-        onClick = { onClick() }
+        onClick = { onClick(item) }
     )
 
 }

+ 0 - 7
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/ItemCard.kt

@@ -11,9 +11,7 @@ package org.mjdev.tvapp.base.ui.components.card
 import android.annotation.SuppressLint
 import androidx.compose.foundation.layout.widthIn
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusState
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.tooling.preview.Preview
@@ -25,7 +23,6 @@ import androidx.tv.material3.CardGlow
 import androidx.tv.material3.CardScale
 import androidx.tv.material3.CardShape
 import androidx.tv.material3.ExperimentalTvMaterial3Api
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
 import org.mjdev.tvapp.base.interfaces.ItemWithDescription
 import org.mjdev.tvapp.base.interfaces.ItemWithImage
 import org.mjdev.tvapp.base.ui.components.complex.FocusableCard
@@ -55,14 +52,11 @@ fun ItemCard(
             placeholder = placeholder
         )
     },
-    focusState: MutableState<FocusState?> = rememberFocusState(),
-    onFocus: (item: Any?) -> Unit = {},
     onClick: (item: Any?) -> Unit = {},
 ) = FocusableCard(
     modifier = modifier.widthIn(max = 320.dp),
     aspectRatio = aspectRatio,
     item = item,
-    focusState = focusState,
     contentScale = contentScale,
     scale = scale,
     shape = shape,
@@ -71,6 +65,5 @@ fun ItemCard(
     glow = glow,
     imageRenderer = imageRenderer,
     placeholder = placeholder,
-    onFocus = onFocus,
     onClick = onClick,
 )

+ 0 - 3
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/card/PhotoCard.kt

@@ -42,19 +42,16 @@ fun PhotoCard(
     aspectRatio: Float? = 16f / 9f,
     placeholder: @Composable () -> Unit = {},
     scale: CardScale = CardDefaults.scale(),
-    onFocus: (item: Any?) -> Unit = {},
     onClick: (item: Any?) -> Unit = {},
 )  {
     ItemCard(
         item = item,
         modifier  = modifier,
-        focusState = focusState,
         contentScale = contentScale,
         aspectRatio=aspectRatio,
         scale = scale,
         imageRenderer = imageRenderer,
         placeholder = placeholder,
         onClick = onClick,
-        onFocus = onFocus
     )
 }

+ 7 - 8
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/carousel/BigCarousel.kt

@@ -18,6 +18,7 @@ import androidx.compose.runtime.mutableIntStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusState
+import androidx.compose.ui.focus.onFocusChanged
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.tooling.preview.Preview
@@ -27,7 +28,6 @@ import androidx.tv.material3.Carousel
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvapp.base.extensions.ComposeExt
 import org.mjdev.tvapp.base.extensions.ComposeExt.isEditMode
-import org.mjdev.tvapp.base.extensions.ComposeExt.isFocused
 import org.mjdev.tvapp.base.ui.components.card.CarouselCard
 
 // todo swipe left and swipe right
@@ -58,16 +58,15 @@ fun BigCarousel(
                 item = items[indexOfCarouselItem],
                 modifier = modifier
                     .fillMaxWidth()
-                    .height(height),
+                    .height(height)
+                    .onFocusChanged { state ->
+                        if (state.isFocused || state.hasFocus) {
+                            onItemSelected(selectedItem())
+                        }
+                    },
                 contentScale = ContentScale.Crop,
                 scale = CardScale.None,
                 focusState = focusState,
-                onFocus = {
-                    if (focusState.isFocused) {
-                        // todo check
-                        onItemSelected(selectedItem())
-                    }
-                },
                 onClick = {
                     onItemClicked(selectedItem())
                 }

+ 10 - 11
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/complex/FocusableBox.kt

@@ -12,9 +12,10 @@ import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.FocusState
+import androidx.compose.ui.focus.onFocusChanged
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.tooling.preview.Preview
@@ -24,16 +25,14 @@ import androidx.tv.material3.Border
 import androidx.tv.material3.ClickableSurfaceDefaults
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.Surface
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
-import org.mjdev.tvapp.base.extensions.ModifierExt.touchable
+import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusRequester
+import org.mjdev.tvapp.base.extensions.ModifierExt.requestFocusOnTouch
 
 @OptIn(ExperimentalTvMaterial3Api::class)
 @Preview
 @Composable
 fun FocusableBox(
     modifier: Modifier = Modifier,
-    onClick: () -> Unit = {},
-    onFocus: () -> Unit = {},
     enabled: Boolean = true,
     tonalElevation: Dp = 0.dp,
     focusedColor: Color = Color.Green,
@@ -44,16 +43,16 @@ fun FocusableBox(
     shape: Shape = RoundedCornerShape(roundCornerSize),
     borderColor: Color = Color.Transparent,
     borderSize: Dp = 0.dp,
-    focusState: MutableState<FocusState?> = rememberFocusState(),
+    focusRequester :FocusRequester= rememberFocusRequester(),
+    onFocusChange: (state: FocusState) -> Unit = {},
+    onClick: () -> Unit = {},
     content: @Composable BoxScope.() -> Unit = {}
 ) {
     Surface(
         onClick = onClick,
-        modifier = modifier.touchable(
-            focusState = focusState,
-            onFocus = { onFocus() },
-            onClick = { onClick() },
-        ),
+        modifier = modifier
+            .onFocusChanged { state -> onFocusChange(state) }
+            .requestFocusOnTouch(focusRequester),
         onLongClick = null,
         enabled = enabled,
         tonalElevation = tonalElevation,

+ 5 - 19
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/complex/FocusableCard.kt

@@ -9,16 +9,13 @@
 package org.mjdev.tvapp.base.ui.components.complex
 
 import android.annotation.SuppressLint
-import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.aspectRatio
 import androidx.compose.foundation.layout.defaultMinSize
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
 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.layout.ContentScale
@@ -33,9 +30,8 @@ import androidx.tv.material3.CardShape
 import androidx.tv.material3.CompactCard
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import org.mjdev.tvapp.base.extensions.ComposeExt
-import org.mjdev.tvapp.base.extensions.ComposeExt.isFocused
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
 import org.mjdev.tvapp.base.extensions.ModifierExt.conditional
+import org.mjdev.tvapp.base.extensions.ModifierExt.requestFocusOnTouch
 import org.mjdev.tvapp.base.interfaces.ItemWithDescription
 import org.mjdev.tvapp.base.interfaces.ItemWithImage
 import org.mjdev.tvapp.base.interfaces.ItemWithSubtitle
@@ -59,7 +55,6 @@ fun FocusableCard(
     border: CardBorder = CardDefaults.colorFocusBorder(Color.Green),
     glow: CardGlow = CardDefaults.colorFocusGlow(Color.Green),
     placeholder: @Composable () -> Unit = {},
-    focusState: MutableState<FocusState?> = rememberFocusState(),
     imageRenderer: @Composable (modifier: Modifier) -> Unit = {
         ImageAny(
             modifier = modifier,
@@ -70,11 +65,11 @@ fun FocusableCard(
         )
     },
     aspectRatio: Float? = 16f / 9f,
-    onFocus: (item: Any?) -> Unit = {},
+    focusRequester : FocusRequester = ComposeExt.rememberFocusRequester(),
+    onFocusChange: (state: FocusState) -> Unit = {},
     onClick: (item: Any?) -> Unit = {},
 ) {
     val isEdit = ComposeExt.isEditMode()
-    val focusRequester = FocusRequester()
     CompactCard(
         scale = scale,
         shape = shape,
@@ -82,22 +77,13 @@ fun FocusableCard(
         border = border,
         glow = glow,
         modifier = modifier
+            .onFocusChanged { state -> onFocusChange(state) }
+            .requestFocusOnTouch(focusRequester)
             .conditional(aspectRatio != null) {
                 aspectRatio(aspectRatio!!)
             }
             .conditional(isEdit) {
                 aspectRatio(16f / 9f).defaultMinSize(80.dp)
-            }
-            .onFocusChanged { state ->
-                focusState.value = state
-            }
-            .focusRequester(focusRequester)
-            .clickable {
-                if (focusState.isFocused) {
-                    onClick(item)
-                } else {
-                    focusRequester.requestFocus()
-                }
             },
         image = {
             imageRenderer(modifier)

+ 3 - 3
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/navigation/NavDrawerContent.kt

@@ -131,10 +131,10 @@ fun NavDrawerContent(
                     drawerState = navController.menuDrawerState,
                     text = menuItem.menuText,
                     icon = menuItem.menuIcon,
-                    onFocus = { id ->
+                    onFocus = { focusId ->
                         navController.openMenu()
-                        focusedIdx.value = id
-                        onDrawerItemFocus(id)
+                        focusedIdx.value = focusId
+                        onDrawerItemFocus(focusId)
                     },
                     onClick = { id ->
                         onDrawerItemClick(id)

+ 5 - 4
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/navigation/NavigationRow.kt

@@ -37,6 +37,7 @@ import androidx.tv.material3.rememberDrawerState
 import org.mjdev.tvapp.base.extensions.ComposeExt.isEditMode
 import org.mjdev.tvapp.base.extensions.ComposeExt.isFocused
 import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
+import org.mjdev.tvapp.base.extensions.ModifierExt.focusState
 import org.mjdev.tvapp.base.ui.components.complex.FocusableBox
 import org.mjdev.tvapp.base.ui.components.icon.IconAny
 import org.mjdev.tvapp.base.ui.components.text.TextAny
@@ -85,13 +86,13 @@ fun NavigationRow(
                     else unFocusedColor
                 ),
                 shape
-            ),
-        focusState = focusState,
+            )
+            .focusState(focusState),
         shape = shape,
         focusedColor = focusedColor.copy(alpha = 0.5f),
         unFocusedColor = Color.Transparent,
-        onFocus = {
-            if (focusState.isFocused) {
+        onFocusChange = { state ->
+            if (state.isFocused || state.hasFocus) {
                 onFocus(id)
             }
         },

+ 3 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/page/Page.kt

@@ -26,7 +26,6 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import org.mjdev.tvapp.base.annotations.TvPreview
-import org.mjdev.tvapp.base.extensions.ModifierExt.touchable
 import org.mjdev.tvapp.base.ui.components.complex.TouchBox
 import org.mjdev.tvapp.base.navigation.MenuItem
 import org.mjdev.tvapp.base.navigation.NavHostControllerEx
@@ -53,9 +52,6 @@ open class Page {
             Modifier
                 .fillMaxSize()
                 .background(backgroundColor, background)
-                .touchable {
-                    freeFocus()
-                }
         ) {
             TouchBox(
                 contentAlignment = Alignment.Center,
@@ -68,7 +64,9 @@ open class Page {
     @Composable
     open fun Content() {
         Column(
-            modifier = Modifier.fillMaxSize().focusable(),
+            modifier = Modifier
+                .fillMaxSize()
+                .focusable(),
             verticalArrangement = Arrangement.Center,
             horizontalAlignment = Alignment.CenterHorizontally,
         ) {

+ 0 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/tv/Clock.kt

@@ -15,12 +15,10 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.collectAsState
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
-import androidx.compose.ui.focus.FocusState
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.platform.LocalContext
@@ -35,7 +33,6 @@ import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.channelFlow
 import kotlinx.coroutines.launch
 import org.mjdev.tvapp.base.extensions.ComposeExt.isEditMode
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
 import org.mjdev.tvapp.base.extensions.ContextExt.dateAsString
 import org.mjdev.tvapp.base.extensions.ContextExt.timeAsString
 import org.mjdev.tvapp.base.extensions.ModifierExt.conditional
@@ -58,7 +55,6 @@ fun Clock(
     contentPadding: Dp = 2.dp,
     showTime: Boolean = true,
     showDate: Boolean = true,
-    focusState: MutableState<FocusState?> = rememberFocusState(),
     onClick: () -> Unit = {},
 ) {
     val isEdit = isEditMode()
@@ -100,7 +96,6 @@ fun Clock(
             .conditional(isEdit) {
                 background(Color.DarkGray, RectangleShape)
             },
-        focusState = focusState,
         shape = RoundedCornerShape(roundSize),
         onClick = onClick
     ) {

+ 10 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/tv/Tabs.kt

@@ -30,6 +30,8 @@ import androidx.tv.material3.TabDefaults
 import androidx.tv.material3.TabRow
 import androidx.tv.material3.TabRowDefaults
 import org.mjdev.tvapp.base.annotations.TvPreview
+import org.mjdev.tvapp.base.extensions.ComposeExt.isFocused
+import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
 import org.mjdev.tvapp.base.extensions.ComposeExt.rememberMutableInteractionSource
 import org.mjdev.tvapp.base.interfaces.ItemWithTitle
 import org.mjdev.tvapp.base.ui.components.complex.FocusableBox
@@ -48,7 +50,7 @@ fun Tabs(
     selectedContentColor: Color = Color.White,
     focusedContentColor: Color = Color.White,
     interactionSource: MutableInteractionSource = rememberMutableInteractionSource(),
-    onItemClick: (index: Int) -> Unit = {}
+    onItemClick: (item: Any?) -> Unit = {}
 ) {
 
     val selectedTabIndex = remember { mutableIntStateOf(0) }
@@ -96,12 +98,15 @@ fun Tabs(
                 },
                 interactionSource = interactionSource
             ) {
-
+                val focusState = rememberFocusState()
                 FocusableBox(
                     focusedColor = Color.Transparent,
-                    onFocus = {
-                        selectedTabIndex.value = index
-                    }
+                    onFocusChange = {
+                        if (focusState.isFocused) {
+                            selectedTabIndex.value = index
+                        }
+                    },
+                    onClick = { onItemClick(items[selectedTabIndex.value]) }
                 ) {
 
                     TextAny(

+ 2 - 6
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/tv/Title.kt

@@ -14,11 +14,9 @@ import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
 import androidx.compose.ui.Alignment.Companion.CenterVertically
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.scale
-import androidx.compose.ui.focus.FocusState
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.tooling.preview.Preview
@@ -45,19 +43,17 @@ fun Title(
     unfocusedShadowColor: Color = Color.Transparent,
     shadowSize: Dp = 6.dp,
     title: Any? = R.string.app_name,
-    focusState: MutableState<FocusState?> = rememberFocusState(),
-    onFocus: () -> Unit = {},
     onClick: () -> Unit = {},
 ) {
     val isEdit = isEditMode()
+    val focusState = rememberFocusState()
 
     FocusableBox(
         modifier = modifier,
-        focusState = focusState,
-        onFocus = onFocus,
         onClick = onClick,
         shape = RoundedCornerShape(8.dp),
         focusedColor = Color.Transparent,
+        onFocusChange = { state -> focusState.value = state }
     ) {
         Row(
             modifier = modifier.padding(8.dp, 8.dp, 8.dp, 8.dp),

+ 0 - 5
app/src/main/kotlin/org/mjdev/tvapp/base/ui/components/tv/UserPic.kt

@@ -12,9 +12,7 @@ import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusState
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.tooling.preview.Preview
@@ -24,7 +22,6 @@ import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.MaterialTheme
 import org.mjdev.tvapp.R
 import org.mjdev.tvapp.base.extensions.ComposeExt.isEditMode
-import org.mjdev.tvapp.base.extensions.ComposeExt.rememberFocusState
 import org.mjdev.tvapp.base.extensions.ModifierExt.conditional
 import org.mjdev.tvapp.base.ui.components.complex.FocusableBox
 import org.mjdev.tvapp.base.ui.components.image.CircleImage
@@ -40,11 +37,9 @@ fun UserPic(
     borderColor: Color = Color.White,
     borderSize: Dp = 2.dp,
     contentPadding: Dp = 2.dp,
-    focusState: MutableState<FocusState?> = rememberFocusState(),
     onClick: () -> Unit = {}
 ) = FocusableBox(
     modifier = modifier.wrapContentSize(),
-    focusState = focusState,
     shape = shape,
     onClick = onClick
 ) {