ソースを参照

fading background

Milan Jurkulak 3 年 前
親
コミット
c7b2d6424c

+ 77 - 48
app/src/main/kotlin/org/mjdev/tvapp/ui/pages/MainPage.kt

@@ -9,16 +9,18 @@
 package org.mjdev.tvapp.ui.pages
 
 import android.annotation.SuppressLint
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Home
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.layout.ContentScale
 import org.mjdev.tvapp.R
 import org.mjdev.tvlib.annotations.TvPreview
 import org.mjdev.tvlib.extensions.HiltExt.appViewModel
@@ -36,6 +38,9 @@ import org.mjdev.tvapp.viewmodel.MainViewModel
 import org.mjdev.tvlib.interfaces.ItemAudio
 import org.mjdev.tvlib.interfaces.ItemPhoto
 import org.mjdev.tvlib.interfaces.ItemVideo
+import org.mjdev.tvlib.interfaces.ItemWithBackground
+import org.mjdev.tvlib.interfaces.ItemWithImage
+import org.mjdev.tvlib.ui.components.tv.FadingPhotoImage
 
 @SuppressLint("ComposableNaming")
 class MainPage : Page() {
@@ -62,12 +67,10 @@ class MainPage : Page() {
         val networkState = remember(viewModel.networkInfo.networkStatus) {
             viewModel.networkInfo.networkStatus
         }.collectAsState(null)
-        val errorState = remember(viewModel.error) {
-            mutableStateOf(viewModel.error.value)
-        }
-        val titleState = remember {
-            mutableStateOf<Any?>(R.string.app_name)
-        }
+
+        val errorState = remember(viewModel.error) { mutableStateOf(viewModel.error.value) }
+        val titleState = remember { mutableStateOf<Any?>(R.string.app_name) }
+        val backgroundState: MutableState<Any?> = remember { mutableStateOf(null) }
 
         val onItemClick: (item: Any?) -> Unit = { item ->
             val dataId = (item as? ItemWithId)?.id
@@ -79,13 +82,16 @@ class MainPage : Page() {
                         val dataUri = (item as? ItemAudio)?.uri
                         navController?.open<PlayerScreen>(dataUri)
                     }
+
                     is ItemVideo -> {
                         val dataUri = (item as? ItemVideo)?.uri
                         navController?.open<PlayerScreen>(dataUri)
                     }
+
                     is ItemPhoto -> {
                         navController?.open<DetailScreen>(item)
                     }
+
                     else -> {
                         navController?.open<DetailScreen>(item)
                     }
@@ -93,56 +99,79 @@ class MainPage : Page() {
             }
         }
 
+        val onItemSelect: (item: Any?) -> Unit = { item ->
+            backgroundState.value = when (item) {
+                is ItemWithBackground<*> -> item.background
+                is ItemWithImage<*> -> item.image
+                else -> {}
+            }
+        }
+
         viewModel.handleError { error ->
             errorState.value = error
         }
 
-        BrowseView(
+        Box(
             modifier = Modifier.fillMaxSize(),
-            appIcon = R.mipmap.ic_launcher,
-            userIcon = R.drawable.milanj,
-            title = titleState.value,
-            messages = messages.value,
-            categories = categoryList.value.map { it.key }.distinct(),
-            featuredItems = featuredMovieList.value,
-            categoriesAndItemsMap = categoryList.value,
-            networkState = networkState,
-            errorState = errorState,
-            backgroundColor = Color.DarkGray,
-            onTitleClicked = {
-                navController?.openMenu()
-            },
-            onItemClicked = onItemClick,
-            customRows = mutableListOf<@Composable () -> Unit>().apply {
-                if (viewModel.appsList.size > 0) {
-                    add { AppsRow(apps = viewModel.appsList) }
-                }
-                if (viewModel.localAudioCursor.count > 0) {
-                    add {
-                        LocalAudioRow(
-                            cursor = viewModel.localAudioCursor,
-                            openItem = { item -> onItemClick(item) }
-                        )
+        ) {
+            FadingPhotoImage(
+                modifier = Modifier.fillMaxSize(),
+                fadingImageState = backgroundState,
+                contrast = 4f,
+                alpha = 0.7f,
+                brightness = -255f,
+                contentScale = ContentScale.Crop
+            )
+            BrowseView(
+                modifier = Modifier.fillMaxSize(),
+                appIcon = R.mipmap.ic_launcher,
+                userIcon = R.drawable.milanj,
+                title = titleState.value,
+                messages = messages.value,
+                categories = categoryList.value.map { it.key }.distinct(),
+                featuredItems = featuredMovieList.value,
+                categoriesAndItemsMap = categoryList.value,
+                networkState = networkState,
+                errorState = errorState,
+                onTitleClicked = {
+                    navController?.openMenu()
+                },
+                onItemFocused = onItemSelect,
+                onItemClicked = onItemClick,
+                customRows = mutableListOf<@Composable () -> Unit>().apply {
+                    if (viewModel.appsList.size > 0) {
+                        add { AppsRow(apps = viewModel.appsList) }
                     }
-                }
-                if (viewModel.localVideoCursor.count > 0) {
-                    add {
-                        LocalVideoRow(
-                            cursor = viewModel.localVideoCursor,
-                            openItem = { item -> onItemClick(item) }
-                        )
+                    if (viewModel.localAudioCursor.count > 0) {
+                        add {
+                            LocalAudioRow(
+                                cursor = viewModel.localAudioCursor,
+                                openItem = { item -> onItemClick(item) },
+                                onItemFocus = onItemSelect,
+                            )
+                        }
                     }
-                }
-                if (viewModel.localPhotoCursor.count > 0) {
-                    add {
-                        LocalPhotosRow(
-                            cursor = viewModel.localPhotoCursor,
-                            openItem = { item -> onItemClick(item) }
-                        )
+                    if (viewModel.localVideoCursor.count > 0) {
+                        add {
+                            LocalVideoRow(
+                                cursor = viewModel.localVideoCursor,
+                                openItem = { item -> onItemClick(item) },
+                                onItemFocus = onItemSelect,
+                            )
+                        }
+                    }
+                    if (viewModel.localPhotoCursor.count > 0) {
+                        add {
+                            LocalPhotosRow(
+                                cursor = viewModel.localPhotoCursor,
+                                openItem = { item -> onItemClick(item) },
+                                onItemFocus = onItemSelect,
+                            )
+                        }
                     }
                 }
-            }
-        )
+            )
+        }
     }
 
 }

+ 1 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/extensions/ComposeExt.kt

@@ -61,7 +61,7 @@ object ComposeExt {
     @Composable
     fun rememberFocusState(
         key: Any?,
-        initial: FocusState? = null
+        initial: FocusState? = null,
     ) = remember(key) {
         mutableStateOf(initial)
     }

+ 2 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/ItemCard.kt

@@ -60,6 +60,7 @@ fun ItemCard(
     },
     cardWidth: Dp = computeCardWidth(),
     focusState: MutableState<FocusState?> = rememberFocusState(item),
+    onFocus: (item: Any?) -> Unit = {},
     onClick: (item: Any?) -> Unit = {},
 ) = FocusableCard(
     modifier = modifier.recomposeHighlighter(),
@@ -76,5 +77,6 @@ fun ItemCard(
     cardWidth = cardWidth,
     imageRenderer = imageRenderer,
     placeholder = placeholder,
+    onFocus = onFocus,
     onClick = onClick,
 )

+ 2 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/card/PhotoCard.kt

@@ -57,6 +57,7 @@ fun PhotoCard(
     aspectRatio: Float = 16f / 9f,
     placeholder: @Composable () -> Unit = {},
     scale: CardScale = CardDefaults.scale(),
+    onFocus: (item: Any?) -> Unit = {},
     onClick: (item: Any?) -> Unit = {},
 ) {
     ItemCard(
@@ -70,6 +71,7 @@ fun PhotoCard(
         scale = scale,
         imageRenderer = imageRenderer,
         placeholder = placeholder,
+        onFocus = onFocus,
         onClick = onClick,
     )
 }

+ 1 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/carousel/BigCarousel.kt

@@ -85,6 +85,7 @@ fun BigCarousel(
                 contentScale = ContentScale.Crop,
                 scale = CardScale.None,
                 focusState = focusState,
+                onFocus = onItemSelected,
                 onClick = {
                     onItemClicked(selectedItem())
                 }

+ 2 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/carousel/CarouselCard.kt

@@ -52,6 +52,7 @@ fun CarouselCard(
             placeholder = placeholder
         )
     },
+    onFocus: (item: Any?) -> Unit = {},
     onClick: (item: Any?) -> Unit = {}
 ) {
     val isEdit = isEditMode()
@@ -68,7 +69,7 @@ fun CarouselCard(
         focusState = focusState,
         placeholder = placeholder,
         imageRenderer = imageRenderer,
+        onFocus = onFocus,
         onClick = { onClick(item) }
     )
-
 }

+ 6 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/complex/FocusableCard.kt

@@ -77,7 +77,12 @@ fun FocusableCard(
     },
     focusRequester: FocusRequester = rememberFocusRequester(item),
     focusState: MutableState<FocusState?> = rememberFocusState(item),
-    onFocusChange: (state: FocusState) -> Unit = {},
+    onFocus: (item: Any?) -> Unit = {},
+    onFocusChange: (state: FocusState) -> Unit = { state ->
+        if (state.isFocused) {
+            onFocus(item)
+        }
+    },
     cardWidth: Dp = computeCardWidth(),
     aspectRatio: Float = 16f / 9f,
     onClick: (item: Any?) -> Unit = {},

+ 2 - 2
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/image/ImageAny.kt

@@ -47,7 +47,7 @@ fun ImageAny(
     contentScale: ContentScale = ContentScale.Fit,
     alpha: Float = DefaultAlpha,
     colorFilter: ColorFilter? = null,
-    placeholder: @Composable () -> Unit = {}, // todo
+    placeholder: @Composable () -> Unit = {}, // todo on error
 ) = BoxWithConstraints(
     modifier = modifier
 ) {
@@ -57,7 +57,7 @@ fun ImageAny(
 
     when (src) {
 
-        null -> placeholder()
+        null, Unit -> placeholder()
 
         Color -> Image(
             ColorDrawable((src as Color).toArgb()).asImageBitmap(width, height),

+ 8 - 2
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/AppsRow.kt

@@ -9,8 +9,10 @@
 package org.mjdev.tvlib.ui.components.tv
 
 import android.content.Context
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.unit.Dp
@@ -32,11 +34,13 @@ fun AppsRow(
     title: Any? = R.string.title_apps,
     rowState: TvLazyListState = rememberTvLazyListState(),
     padding: Dp = 8.dp,
-    backgroundColor: Color = Color.DarkGray,
+    backgroundColor: Color = Color.DarkGray.copy(alpha = 0.3f),
+    roundCornerSize: Dp = 8.dp,
+    backgroundShape: Shape = RoundedCornerShape(roundCornerSize),
     startApp: Context.(app: App?) -> Unit = { app ->
         startActivity(app?.intent)
     },
-    apps : List<App> = rememberAppsManager()
+    apps: List<App> = rememberAppsManager()
 ) {
     val context: Context = LocalContext.current
     val cardWidth = computeCardWidth(3f)
@@ -49,6 +53,8 @@ fun AppsRow(
             cardWidth = cardWidth,
             contentScale = ContentScale.Fit,
             backgroundColor = backgroundColor,
+            roundCornerSize = roundCornerSize,
+            backgroundShape = backgroundShape,
             onItemClick = { app ->
                 startApp(context, app as? App)
             },

+ 6 - 11
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/BrowseView.kt

@@ -8,23 +8,17 @@
 
 package org.mjdev.tvlib.ui.components.tv
 
-import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.tv.material3.ExperimentalTvMaterial3Api
-import org.mjdev.tvapp.base.ui.components.tv.Header
 import org.mjdev.tvlib.annotations.TvPreview
 import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
 import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
@@ -55,9 +49,6 @@ fun BrowseView(
     ),
     networkState: State<NetworkStatus?> = mutableStateOf(NetworkStatus.Unknown),
     errorState: State<Throwable?> = mutableStateOf(null),
-    backgroundColor: Color = Color.DarkGray,
-    roundCornerSize: Dp = 0.dp,
-    backgroundShape: Shape = RoundedCornerShape(roundCornerSize),
     verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(32.dp),
     contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
     customRows: List<@Composable () -> Unit> = emptyList(),
@@ -65,14 +56,14 @@ fun BrowseView(
     onClockClicked: () -> Unit = {},
     onMessageBadgeClicked: () -> Unit = {},
     onUserPicClicked: () -> Unit = {},
+    onItemFocused: (item: Any?) -> Unit = {},
     onItemClicked: (item: Any?) -> Unit = {}
 ) {
     val isEdit = isEditMode()
     ScrollableTvLazyRow(
         modifier = modifier
             .recomposeHighlighter()
-            .fillMaxSize()
-            .background(backgroundColor, backgroundShape),
+            .fillMaxSize(),
         verticalArrangement = verticalArrangement,
         contentPadding = contentPadding
     ) {
@@ -115,6 +106,7 @@ fun BrowseView(
             BigCarousel(
                 modifier = Modifier.recomposeHighlighter(),
                 items = featuredItems,
+                onItemSelected = onItemFocused,
                 onItemClicked = onItemClicked
             )
         }
@@ -125,6 +117,9 @@ fun BrowseView(
             CategoryRow(
                 title = (entry.first as? ItemWithTitle<*>)?.title,
                 items = entry.second,
+                onItemFocus = {
+                    onItemFocused(it)
+                },
                 onItemClick = onItemClicked
             )
         }

+ 19 - 9
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/CategoryRow.kt

@@ -15,13 +15,14 @@ import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.text.font.FontWeight
@@ -47,7 +48,10 @@ fun CategoryRow(
     padding: Dp = 8.dp,
     cardWidth: Dp = computeCardWidth(),
     contentScale: ContentScale = ContentScale.Crop,
-    backgroundColor: Color = Color.DarkGray,
+    backgroundColor: Color = Color.DarkGray.copy(alpha = 0.3f),
+    roundCornerSize: Dp = 8.dp,
+    backgroundShape: Shape = RoundedCornerShape(roundCornerSize),
+    onItemFocus: (item: Any?) -> Unit = {},
     onItemClick: (item: Any?) -> Unit = {},
     contentOfItem: @Composable (item: Any?) -> Unit = { item ->
         PhotoCard(
@@ -55,17 +59,20 @@ fun CategoryRow(
             contentScale = contentScale,
             cardWidth = cardWidth,
             onClick = onItemClick,
+            onFocus = onItemFocus
         )
     },
 ) {
     val scrollDelta = remember { mutableFloatStateOf(0f) }
     Column(
-        modifier = Modifier.recomposeHighlighter()
+        modifier = Modifier
+            .recomposeHighlighter()
             .fillMaxWidth()
-            .background(backgroundColor, RectangleShape)
+            .background(backgroundColor, backgroundShape)
     ) {
         TextAny(
-            modifier = Modifier.recomposeHighlighter()
+            modifier = Modifier
+                .recomposeHighlighter()
                 .fillMaxWidth()
                 .padding(padding / 2, padding / 2),
             text = title,
@@ -74,11 +81,14 @@ fun CategoryRow(
         )
         TVRow(
             horizontalArrangement = Arrangement.spacedBy(padding),
-            modifier = Modifier.fillMaxWidth().pointerInput(Unit) {
-                detectDragGestures { _, dragAmount ->
-                    scrollDelta.value = dragAmount.x
+            modifier = Modifier
+                .fillMaxWidth()
+                .pointerInput(Unit) {
+                    detectDragGestures { _, dragAmount ->
+                        scrollDelta.value = dragAmount.x
+                    }
                 }
-            }.recomposeHighlighter(),
+                .recomposeHighlighter(),
             state = rowState,
             contentPadding = (padding.value * 1.3).dp, // todo due border & glow
         ) {

+ 8 - 3
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/CursorRow.kt

@@ -19,13 +19,14 @@ import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.platform.LocalContext
@@ -53,7 +54,9 @@ fun CursorRow(
     title: Any? = null,
     rowState: TvLazyListState = rememberTvLazyListState(),
     padding: Dp = 16.dp,
-    backgroundColor: Color = Color.DarkGray,
+    backgroundColor: Color = Color.DarkGray.copy(alpha = 0.3f),
+    roundCornerSize: Dp = 8.dp,
+    backgroundShape: Shape = RoundedCornerShape(roundCornerSize),
     cardWidth: Dp = computeCardWidth(),
     contentScale: ContentScale = ContentScale.Crop,
     uri: Uri? = null,
@@ -70,6 +73,7 @@ fun CursorRow(
         sortOrder = sortOrder,
         transform = transform
     ),
+    onItemFocus: (item: Any?) -> Unit = {},
     openItem: Context.(item: Any?) -> Unit = {},
 ) {
     val context: Context = LocalContext.current
@@ -79,7 +83,7 @@ fun CursorRow(
             modifier = Modifier
                 .recomposeHighlighter()
                 .fillMaxWidth()
-                .background(backgroundColor, RectangleShape)
+                .background(backgroundColor, backgroundShape)
         ) {
             TextAny(
                 modifier = Modifier
@@ -111,6 +115,7 @@ fun CursorRow(
                         item = cursor.getData(idx),
                         contentScale = contentScale,
                         cardWidth = cardWidth,
+                        onFocus = onItemFocus,
                         onClick = { i ->
                             openItem(context, i)
                         },

+ 74 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/FadingPhotoImage.kt

@@ -0,0 +1,74 @@
+/*
+ * 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.tv
+
+import androidx.annotation.FloatRange
+import androidx.compose.animation.Crossfade
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.shape.RoundedCornerShape
+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.draw.alpha
+import androidx.compose.ui.draw.blur
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import org.mjdev.tvlib.ui.components.image.PhotoImage
+
+@Composable
+fun FadingPhotoImage(
+    modifier: Modifier = Modifier,
+    initialImage: Any? = null,
+    fadingImageState: MutableState<Any?> = remember { mutableStateOf(initialImage) },
+    animationDuration: Int = 1000,
+    alpha: Float = 0.6f,
+    blurRadius: Dp = 4.dp,
+    @FloatRange(from = 0.0, to = 10.0)
+    contrast: Float = 4f,
+    @FloatRange(from = -255.0, to = 255.0)
+    brightness: Float = -255f,
+    contentScale: ContentScale = ContentScale.Crop,
+    placeholder: @Composable () -> Unit = {},
+    borderSize: Dp = 0.dp,
+    borderColor: Color = Color.Transparent,
+    roundCornerSize: Dp = 0.dp,
+    shape: Shape = RoundedCornerShape(roundCornerSize),
+    colorFilter: ColorFilter? = null,
+    contentDescription: String? = null,
+    alignment: Alignment = Alignment.Center,
+) {
+    Crossfade(
+        fadingImageState.value,
+        animationSpec = tween(animationDuration)
+    ) { targetState ->
+        PhotoImage(
+            modifier = modifier
+                .alpha(alpha)
+                .blur(radius = blurRadius),
+            src = targetState,
+            contrast = contrast,
+            brightness = brightness,
+            contentScale = contentScale,
+            placeholder = placeholder,
+            borderSize = borderSize,
+            borderColor = borderColor,
+            shape = shape,
+            colorFilter = colorFilter,
+            contentDescription = contentDescription,
+            alignment = alignment
+        )
+    }
+}

+ 4 - 7
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/Header.kt

@@ -6,7 +6,7 @@
  *  w: https://mjdev.org
  */
 
-package org.mjdev.tvapp.base.ui.components.tv
+package org.mjdev.tvlib.ui.components.tv
 
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Arrangement
@@ -33,9 +33,6 @@ import org.mjdev.tvlib.extensions.ComposeExt.isEditMode
 import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
 import org.mjdev.tvlib.R
 import org.mjdev.tvlib.ui.components.badge.Badge
-import org.mjdev.tvlib.ui.components.tv.Clock
-import org.mjdev.tvlib.ui.components.tv.Title
-import org.mjdev.tvlib.ui.components.tv.UserPic
 
 @TvPreview
 @Composable
@@ -46,8 +43,8 @@ fun Header(
     fontSize: TextUnit = 24.sp,
     fontWeight: FontWeight = FontWeight.Bold,
     color: Color = Color.White,
-    backgroundColor: Color = Color.DarkGray,
-    roundSize: Dp = 0.dp,
+    backgroundColor: Color = Color.DarkGray.copy(alpha = 0.3f),
+    roundSize: Dp = 8.dp,
     padding: Dp = 0.dp,
     contentPadding: Dp = 2.dp,
     messagesCount: Int = 0,
@@ -62,7 +59,7 @@ fun Header(
             .recomposeHighlighter()
             .fillMaxWidth()
             .background(backgroundColor, RoundedCornerShape(roundSize))
-            .padding(padding + roundSize),
+            .padding(padding),
         contentAlignment = Alignment.Center
     ) {
         Row(

+ 9 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/LocalAudioRow.kt

@@ -11,8 +11,10 @@ package org.mjdev.tvlib.ui.components.tv
 import android.content.ContentResolver
 import android.content.Context
 import android.database.Cursor
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
@@ -32,7 +34,9 @@ fun LocalAudioRow(
     title: Any? = R.string.title_audio_local,
     rowState: TvLazyListState = rememberTvLazyListState(),
     padding: Dp = 8.dp,
-    backgroundColor: Color = Color.DarkGray,
+    backgroundColor: Color = Color.DarkGray.copy(alpha = 0.3f),
+    roundCornerSize: Dp = 8.dp,
+    backgroundShape: Shape = RoundedCornerShape(roundCornerSize),
     selection: String? = null,
     selectionArgs: Array<String>? = null,
     sortOrder: String? = AudioItem.SORT_ORDER_DATE_DESC,
@@ -48,12 +52,15 @@ fun LocalAudioRow(
         sortOrder = sortOrder,
         transform = transform
     ),
+    onItemFocus: (item: Any?) -> Unit = {},
     openItem: Context.(item: Any?) -> Unit = {},
 ) = CursorRow(
     title = title,
     rowState = rowState,
     padding = padding,
     backgroundColor = backgroundColor,
+    roundCornerSize = roundCornerSize,
+    backgroundShape = backgroundShape,
     cardWidth = cardWidth,
     contentScale = contentScale,
     uri = AudioItem.URI,
@@ -62,6 +69,7 @@ fun LocalAudioRow(
     selectionArgs = selectionArgs,
     sortOrder = sortOrder,
     transform = transform,
+    onItemFocus = onItemFocus,
     openItem = openItem,
     cursor = cursor
 )

+ 9 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/LocalPhotosRow.kt

@@ -11,8 +11,10 @@ package org.mjdev.tvlib.ui.components.tv
 import android.content.ContentResolver
 import android.content.Context
 import android.database.Cursor
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
@@ -32,7 +34,9 @@ fun LocalPhotosRow(
     title: Any? = R.string.title_photo_local,
     rowState: TvLazyListState = rememberTvLazyListState(),
     padding: Dp = 8.dp,
-    backgroundColor: Color = Color.DarkGray,
+    backgroundColor: Color = Color.DarkGray.copy(alpha = 0.3f),
+    roundCornerSize: Dp = 8.dp,
+    backgroundShape: Shape = RoundedCornerShape(roundCornerSize),
     selection: String? = null,
     selectionArgs: Array<String>? = null,
     sortOrder: String? = PhotoItem.SORT_ORDER_DATE_DESC,
@@ -48,12 +52,15 @@ fun LocalPhotosRow(
         sortOrder = sortOrder,
         transform = transform
     ),
+    onItemFocus: (item: Any?) -> Unit = {},
     openItem: Context.(item: Any?) -> Unit = {},
 ) = CursorRow(
     title = title,
     rowState = rowState,
     padding = padding,
     backgroundColor = backgroundColor,
+    backgroundShape = backgroundShape,
+    roundCornerSize = roundCornerSize,
     cardWidth = cardWidth,
     contentScale = contentScale,
     uri = PhotoItem.URI,
@@ -63,5 +70,6 @@ fun LocalPhotosRow(
     sortOrder = sortOrder,
     transform = transform,
     openItem = openItem,
+    onItemFocus = onItemFocus,
     cursor = cursor
 )

+ 9 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/LocalVideoRow.kt

@@ -11,8 +11,10 @@ package org.mjdev.tvlib.ui.components.tv
 import android.content.ContentResolver
 import android.content.Context
 import android.database.Cursor
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
@@ -32,7 +34,9 @@ fun LocalVideoRow(
     title: Any? = R.string.title_video_local,
     rowState: TvLazyListState = rememberTvLazyListState(),
     padding: Dp = 8.dp,
-    backgroundColor: Color = Color.DarkGray,
+    backgroundColor: Color = Color.DarkGray.copy(alpha = 0.3f),
+    roundCornerSize: Dp = 8.dp,
+    backgroundShape: Shape = RoundedCornerShape(roundCornerSize),
     selection: String? = null,
     selectionArgs: Array<String>? = null,
     sortOrder: String? = VideoItem.SORT_ORDER_DATE_DESC,
@@ -48,6 +52,7 @@ fun LocalVideoRow(
         sortOrder = sortOrder,
         transform = transform
     ),
+    onItemFocus: (item: Any?) -> Unit = {},
     openItem: Context.(item: Any?) -> Unit = {},
 ) {
     CursorRow(
@@ -55,6 +60,8 @@ fun LocalVideoRow(
         rowState = rowState,
         padding = padding,
         backgroundColor = backgroundColor,
+        backgroundShape = backgroundShape,
+        roundCornerSize = roundCornerSize,
         cardWidth = cardWidth,
         contentScale = contentScale,
         uri = VideoItem.URI,
@@ -64,6 +71,7 @@ fun LocalVideoRow(
         sortOrder = sortOrder,
         transform = { c -> VideoItem(contentResolver, c) },
         openItem = openItem,
+        onItemFocus = onItemFocus,
         cursor = cursor
     )
 }